mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-23 15:00:34 +01:00
2146 lines
163 KiB
Python
2146 lines
163 KiB
Python
# NOTE: For detailed documentation, refer to https://docs.corelightning.org/docs/writing-json-schemas.
|
|
# NOTE: Set the test `TIMEOUT` to greater than 3 seconds to prevent failures caused by waiting on the bitcoind response.
|
|
# The `dev-bitcoind-poll` interval is 3 seconds, so a shorter timeout may result in test failures.
|
|
# NOTE: Different nodes are selected to record examples based on data availability, quality, and volume.
|
|
# For example, node `l1` is used to capture examples for `listsendpays`, whereas node `l2` is utilized for `listforwards`.
|
|
|
|
|
|
from fixtures import * # noqa: F401,F403
|
|
from fixtures import TEST_NETWORK
|
|
from pyln.client import RpcError, Millisatoshi # type: ignore
|
|
from pyln.testing.utils import GENERATE_EXAMPLES
|
|
from utils import only_one, mine_funding_to_announce, sync_blockheight, wait_for, first_scid, serialize_payload_tlv, serialize_payload_final_tlv
|
|
import sys
|
|
import os
|
|
import re
|
|
import time
|
|
import pytest
|
|
import unittest
|
|
import json
|
|
import logging
|
|
import ast
|
|
import subprocess
|
|
|
|
CWD = os.getcwd()
|
|
CLN_VERSION = 'v'
|
|
with open(os.path.join('.version'), 'r') as f:
|
|
CLN_VERSION = CLN_VERSION + f.read().strip()
|
|
|
|
FUND_WALLET_AMOUNT_SAT = 200000000
|
|
FUND_CHANNEL_AMOUNT_SAT = 10**6
|
|
REGENERATING_RPCS = []
|
|
ALL_RPC_EXAMPLES = {}
|
|
EXAMPLES_JSON = {}
|
|
LOG_FILE = './tests/autogenerate-examples-status.log'
|
|
TEMP_EXAMPLES_FILE = './tests/autogenerate-examples.json'
|
|
IGNORE_RPCS_LIST = ['dev-splice', 'reckless', 'sql-template']
|
|
|
|
# Constants for replacing values in examples
|
|
NEW_VALUES_LIST = {
|
|
'root_dir': '/root/lightning',
|
|
'tmp_dir': '/tmp/.lightning',
|
|
'str_1': '1',
|
|
'num_1': 1,
|
|
'balance_msat_1': 202050000000,
|
|
'fees_paid_msat_1': 5020000,
|
|
'bytes_used': 1630000,
|
|
'bytes_max': 10485760,
|
|
'assocdata_1': 'assocdata0' + ('01' * 27),
|
|
'hsm_secret_cdx_1': 'cl10leetsd35kw6r5de5kueedxyesqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqluplcg0lxenqd',
|
|
'error_message_1': 'All addresses failed: 127.0.0.1:19736: Cryptographic handshake: peer closed connection (wrong key?). ',
|
|
'configs_3_addr2': "127.0.0.1:19735",
|
|
'bitcoin-rpcport': 18332,
|
|
'grpc-port': 9736,
|
|
'blockheight_110': 110,
|
|
'blockheight_130': 130,
|
|
'blockheight_160': 160,
|
|
'script_pubkey_1': 'scriptpubkey' + ('01' * 28),
|
|
'script_pubkey_2': 'scriptpubkey' + ('02' * 28),
|
|
'onion_1': 'onion' + ('10' * 1363),
|
|
'onion_2': 'onion' + ('20' * 1363),
|
|
'onion_3': 'onion' + ('30' * 1363),
|
|
'shared_secrets_1': ['sharedsecret' + ('10' * 26), 'sharedsecret' + ('11' * 26), 'sharedsecret' + ('12' * 26)],
|
|
'shared_secrets_2': ['sharedsecret' + ('20' * 26), 'sharedsecret' + ('21' * 26), 'sharedsecret' + ('22' * 26)],
|
|
'invreq_id_1': 'invreqid' + ('01' * 28),
|
|
'invreq_id_2': 'invreqid' + ('02' * 28),
|
|
'invreq_id_l1_l22': 'invreqid' + ('03' * 28),
|
|
'invoice_1': 'lni1qqg0qe' + ('01' * 415),
|
|
'invoice_2': 'lni1qqg0qe' + ('02' * 415),
|
|
'invoice_3': 'lni1qqg0qe' + ('03' * 415),
|
|
'funding_txid_1': 'fundingtxid001' + ('01' * 25),
|
|
'funding_txid_2': 'fundingtxid002' + ('02' * 25),
|
|
'signature_1': 'dcde30c4bb50bed221009d' + ('01' * 60),
|
|
'signature_2': 'dcdepay30c4bb50bed209d' + ('02' * 60),
|
|
'destination_1': 'bcrt1p52' + ('01' * 28),
|
|
'destination_2': 'bcrt1qcqqv' + ('01' * 17),
|
|
'destination_3': 'bcrt1phtprcvhz' + ('02' * 25),
|
|
'destination_4': 'bcrt1p00' + ('02' * 28),
|
|
'destination_5': 'bcrt1p00' + ('03' * 28),
|
|
'destination_6': 'bcrt1p00' + ('04' * 28),
|
|
'destination_7': 'bcrt1p338x' + ('07' * 28),
|
|
'funding_serial_1': 17725655605188010000,
|
|
'funding_serial_2': 17725655605188020000,
|
|
'funding_serial_3': 17725655605188030000,
|
|
'funding_serial_4': 17725655605188040000,
|
|
'funding_serial_5': 17725655605188050000,
|
|
'l1_id': 'nodeid' + ('01' * 30),
|
|
'l2_id': 'nodeid' + ('02' * 30),
|
|
'l3_id': 'nodeid' + ('03' * 30),
|
|
'l4_id': 'nodeid' + ('04' * 30),
|
|
'l5_id': 'nodeid' + ('05' * 30),
|
|
'l10_id': 'nodeid' + ('10' * 30),
|
|
'l12_id': 'nodeid' + ('12' * 30),
|
|
'l1_alias': 'JUNIORBEAM',
|
|
'l2_alias': 'SILENTARTIST',
|
|
'l3_alias': 'HOPPINGFIRE',
|
|
'l4_alias': 'JUNIORFELONY',
|
|
'l2_port': 19735,
|
|
'l3_port': 19736,
|
|
'l1_addr': '127.0.0.1:19734',
|
|
'l2_addr': '127.0.0.1:19735',
|
|
'l3_addr': '127.0.0.1:19736',
|
|
'l4_addr': '127.0.0.1:19737',
|
|
'l5_addr': '127.0.0.1:19738',
|
|
'l6_addr': '127.0.0.1:19739',
|
|
'c12': '109x1x1',
|
|
'c23': '111x1x1',
|
|
'c23_2': '123x1x1',
|
|
'c25': '115x1x1',
|
|
'c34': '125x1x1',
|
|
'c34_2': '130x1x1',
|
|
'c35_tx': '020000000000305fundchanneltx' + ('35000' * 99),
|
|
'c41_tx': '020000000000401fundchanneltx' + ('41000' * 99),
|
|
'upgrade_tx': '02000000000101upgd' + ('20000' * 34),
|
|
'close1_tx': '02000000000101cls0' + ('01' * 200),
|
|
'close2_tx': '02000000000101cls1' + ('02' * 200),
|
|
'send_tx_1': '02000000000101sendpt' + ('64000' * 100),
|
|
'send_tx_2': '02000000000102sendpt' + ('65000' * 100),
|
|
'tx_55': '02000000000155multiw' + ('55000' * 100),
|
|
'tx_56': '02000000000155multiw' + ('56000' * 100),
|
|
'tx_61': '02000000000155multiw' + ('61000' * 100),
|
|
'tx_91': '020000000001wthdrw' + ('91000' * 100),
|
|
'tx_92': '020000000002wthdrw' + ('92000' * 100),
|
|
'unsigned_tx_1': '0200000000' + ('0002' * 66),
|
|
'unsigned_tx_3': '0200000000' + ('0006' * 66),
|
|
'unsigned_tx_4': '0200000000' + ('0008' * 66),
|
|
'multi_tx_1': '02000000000101multif' + ('50000' * 100),
|
|
'multi_tx_2': '02000000000102multif' + ('60000' * 100),
|
|
'ocs_tx_1': '02000000000101sgpsbt' + ('11000' * 100),
|
|
'ocs_tx_2': '02000000000101sgpsbt' + ('12000' * 100),
|
|
'txsend_tx_1': '02000000000101txsend' + ('00011' * 100),
|
|
'txsend_tx_2': '02000000000101txsend' + ('00022' * 100),
|
|
'c12_txid': 'channeltxid' + ('120000' * 9),
|
|
'c23_txid': 'channeltxid' + ('230000' * 9),
|
|
'c23_2_txid': 'channeltxid' + ('230200' * 9),
|
|
'c34_txid': 'channeltxid' + ('340000' * 9),
|
|
'c34_2_txid': 'channeltxid' + ('340200' * 9),
|
|
'c35_txid': 'channeltxid' + ('350000' * 9),
|
|
'c41_txid': 'channeltxid' + ('410000' * 9),
|
|
'c1112_txid': 'channeltxid' + ('111200' * 9),
|
|
'upgrade_txid': 'txidupgrade' + ('200000' * 9),
|
|
'close1_txid': 'txid' + ('01' * 30),
|
|
'close2_txid': 'txid' + ('02' * 30),
|
|
'send_txid_1': 'txid' + ('64000' * 11),
|
|
'send_txid_2': 'txid' + ('65000' * 11),
|
|
'txid_55': 'txid' + ('55000' * 11),
|
|
'txid_56': 'txid' + ('56000' * 11),
|
|
'txid_61': 'txid' + ('61000' * 11),
|
|
'withdraw_txid_l21': 'txidwithdraw21' + ('91000' * 10),
|
|
'withdraw_txid_l22': 'txidwithdraw22' + ('92000' * 10),
|
|
'txprep_txid_1': 'txidtxprep0001' + ('00001' * 10),
|
|
'txprep_txid_2': 'txidtxprep0002' + ('00002' * 10),
|
|
'txprep_txid_3': 'txidtxprep0003' + ('00003' * 10),
|
|
'txprep_txid_4': 'txidtxprep0004' + ('00004' * 10),
|
|
'multi_txid_1': 'channeltxid010' + ('50000' * 10),
|
|
'multi_txid_2': 'channeltxid020' + ('60000' * 10),
|
|
'utxo_1': 'utxo' + ('01' * 30),
|
|
'ocs_txid_1': 'txidocsigned10' + ('11000' * 10),
|
|
'ocs_txid_2': 'txidocsigned10' + ('12000' * 10),
|
|
'c12_channel_id': 'channelid0' + ('120000' * 9),
|
|
'c23_channel_id': 'channelid0' + ('230000' * 9),
|
|
'c23_2_channel_id': 'channelid0' + ('230200' * 9),
|
|
'c25_channel_id': 'channelid0' + ('250000' * 9),
|
|
'c34_channel_id': 'channelid0' + ('340000' * 9),
|
|
'c34_2_channel_id': 'channelid0' + ('340200' * 9),
|
|
'c35_channel_id': 'channelid0' + ('350000' * 9),
|
|
'c41_channel_id': 'channelid0' + ('410000' * 9),
|
|
'c78_channel_id': 'channelid0' + ('780000' * 9),
|
|
'c1112_channel_id': 'channelid0' + ('111200' * 9),
|
|
'c910_channel_id_1': 'channelid' + ('09101' * 11),
|
|
'c910_channel_id_2': 'channelid' + ('09102' * 11),
|
|
'mf_channel_id_1': 'channelid' + ('11000' * 11),
|
|
'mf_channel_id_2': 'channelid' + ('12000' * 11),
|
|
'mf_channel_id_3': 'channelid' + ('13000' * 11),
|
|
'mf_channel_id_4': 'channelid' + ('15200' * 11),
|
|
'mf_channel_id_5': 'channelid' + ('12400' * 11),
|
|
'time_at_800': 1738000000,
|
|
'time_at_850': 1738500000,
|
|
'time_at_900': 1739000000,
|
|
'bolt11_l11': 'lnbcrt100n1pnt2' + ('bolt11invl010100000000' * 10),
|
|
'bolt11_l12': 'lnbcrt100n1pnt2' + ('bolt11invl010200000000' * 10),
|
|
'bolt11_l13': 'lnbcrt100n1pnt2' + ('bolt11invl010300000000' * 10),
|
|
'bolt11_l14': 'lnbcrt100n1pnt2' + ('bolt11invl010400000000' * 10),
|
|
'bolt11_l21': 'lnbcrt100n1pnt2' + ('bolt11invl020100000000' * 10),
|
|
'bolt11_l22': 'lnbcrt100n1pnt2' + ('bolt11invl020200000000' * 10),
|
|
'bolt11_l23': 'lnbcrt100n1pnt2' + ('bolt11invl020300000000' * 10),
|
|
'bolt11_l24': 'lnbcrt100n1pnt2' + ('bolt11invl020400000000' * 10),
|
|
'bolt11_l25': 'lnbcrt100n1pnt2' + ('bolt11invl020500000000' * 10),
|
|
'bolt11_l26': 'lnbcrt100n1pnt2' + ('bolt11invl020600000000' * 10),
|
|
'bolt11_l27': 'lnbcrt100n1pnt2' + ('bolt11invl020700000000' * 10),
|
|
'bolt11_l31': 'lnbcrt100n1pnt2' + ('bolt11invl030100000000' * 10),
|
|
'bolt11_l33': 'lnbcrt100n1pnt2' + ('bolt11invl030300000000' * 10),
|
|
'bolt11_l34': 'lnbcrt100n1pnt2' + ('bolt11invl030400000000' * 10),
|
|
'bolt11_l41': 'lnbcrt100n1pnt2' + ('bolt11invl040100000000' * 10),
|
|
'bolt11_l66': 'lnbcrt100n1pnt2' + ('bolt11invl060600000000' * 10),
|
|
'bolt11_l67': 'lnbcrt100n1pnt2' + ('bolt11invl060700000000' * 10),
|
|
'bolt11_wt_1': 'lnbcrt222n1pnt3005720bolt11wtinv' + ('01' * 160),
|
|
'bolt11_wt_2': 'lnbcrt222n1pnt3005720bolt11wtinv' + ('02' * 160),
|
|
'bolt11_di_1': 'lnbcrt222n1pnt3005720bolt11300' + ('01' * 170),
|
|
'bolt11_di_2': 'lnbcrt222n1pnt3005720bolt11300' + ('01' * 170),
|
|
'bolt11_dp_1': 'lnbcrt222n1pnt3005720bolt11400' + ('01' * 170),
|
|
'bolt12_l21': 'lno1qgsq000bolt' + ('21000' * 24),
|
|
'bolt12_l22': 'lno1qgsq000bolt' + ('22000' * 24),
|
|
'bolt12_l23': 'lno1qgsq000bolt' + ('23000' * 24),
|
|
'bolt12_l24': 'lno1qgsq000bolt' + ('24000' * 24),
|
|
'bolt12_si_1': 'lno1qgsq000bolt' + ('si100' * 24),
|
|
'offerid_l21': 'offeridl' + ('2100000' * 8),
|
|
'offerid_l22': 'offeridl' + ('2200000' * 8),
|
|
'offerid_l23': 'offeridl' + ('2300000' * 8),
|
|
'payment_hash_l11': 'paymenthashinvl0' + ('1100' * 12),
|
|
'payment_hash_l21': 'paymenthashinvl0' + ('2100' * 12),
|
|
'payment_hash_l22': 'paymenthashinvl0' + ('2200' * 12),
|
|
'payment_hash_l27': 'paymenthashinvl0' + ('2700' * 12),
|
|
'payment_hash_l31': 'paymenthashinvl0' + ('3100' * 12),
|
|
'payment_hash_l24': 'paymenthashinvl0' + ('2400' * 12),
|
|
'payment_hash_l25': 'paymenthashinvl0' + ('2500' * 12),
|
|
'payment_hash_l26': 'paymenthashinvl0' + ('2600' * 12),
|
|
'payment_hash_l33': 'paymenthashinvl0' + ('3300' * 12),
|
|
'payment_hash_l34': 'paymenthashinvl0' + ('3400' * 12),
|
|
'payment_hash_key_1': 'paymenthashkey01' + ('k101' * 12),
|
|
'payment_hash_key_2': 'paymenthashkey02' + ('k201' * 12),
|
|
'payment_hash_key_3': 'paymenthashkey03' + ('k301' * 12),
|
|
'payment_hash_cmd_pay_1': 'paymenthashcmdpy' + ('cp10' * 12),
|
|
'payment_hash_si_1': 'paymenthashsdinv' + ('si10' * 12),
|
|
'payment_hash_wspc_1': 'paymenthashwtspct2' + ('01' * 23),
|
|
'payment_hash_winv_1': 'paymenthashwaitinv' + ('01' * 23),
|
|
'payment_hash_winv_2': 'paymenthashwaitinv' + ('02' * 23),
|
|
'payment_hash_di_1': 'paymenthashdelinv1' + ('01' * 23),
|
|
'payment_hash_di_2': 'paymenthashdelinv2' + ('02' * 23),
|
|
'payment_hash_dp_1': 'paymenthashdelpay1' + ('01' * 23),
|
|
'payment_hash_dp_2': 'paymenthashdelpay2' + ('02' * 23),
|
|
'payment_hash_dp_3': 'paymenthashdelpay3' + ('03' * 23),
|
|
'payment_preimage_1': 'paymentpreimage1' + ('01' * 24),
|
|
'payment_preimage_2': 'paymentpreimage2' + ('02' * 24),
|
|
'payment_preimage_3': 'paymentpreimage3' + ('03' * 24),
|
|
'payment_preimage_ep_1': 'paymentpreimagep' + ('01' * 24),
|
|
'payment_preimage_ep_2': 'paymentpreimagep' + ('02' * 24),
|
|
'payments_preimage_i_1': 'paymentpreimagei' + ('01' * 24),
|
|
'payments_preimage_w_1': 'paymentpreimagew' + ('01' * 24),
|
|
'payment_preimage_cmd_1': 'paymentpreimagec' + ('01' * 24),
|
|
'payment_preimage_r_1': 'paymentpreimager' + ('01' * 24),
|
|
'payment_preimage_r_2': 'paymentpreimager' + ('02' * 24),
|
|
'payment_preimage_wi_1': 'paymentpreimagewaitinv0' + ('01' * 21),
|
|
'payment_preimage_wi_2': 'paymentpreimagewaitinv0' + ('02' * 21),
|
|
'payment_preimage_di_1': 'paymentpreimagedelinv01' + ('01' * 21),
|
|
'payment_preimage_dp_1': 'paymentpreimgdp1' + ('01' * 24),
|
|
'payment_preimage_xp_1': 'paymentpreimgxp1' + ('01' * 24),
|
|
'payment_preimage_xp_2': 'paymentpreimgxp2' + ('02' * 24),
|
|
'payment_preimage_io_1': 'paymentpreimgio1' + ('03' * 24),
|
|
'payment_secret_l11': 'paymentsecretinvl00' + ('11000' * 9),
|
|
'payment_secret_l22': 'paymentsecretinvl00' + ('22000' * 9),
|
|
'payment_secret_l31': 'paymentsecretinvl00' + ('31000' * 9),
|
|
'init_psbt_1': 'cHNidP8BAgpsbt10' + ('01' * 52),
|
|
'init_psbt_2': 'cHNidP8BAgpsbt20' + ('02' * 84),
|
|
'init_psbt_3': 'cHNidP8BAgpsbt30' + ('03' * 92),
|
|
'upgrade_psbt_1': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('110000' * 100),
|
|
'psbt_1': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('711000' * 120),
|
|
'psbt_2': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('712000' * 120),
|
|
'psbt_3': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('713000' * 120),
|
|
'psbt_4': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('714000' * 120),
|
|
'psbt_5_1': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('715100' * 120),
|
|
'psbt_5_2': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('715200' * 120),
|
|
'psbt_6_1': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('716100' * 120),
|
|
'psbt_6_2': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('716200' * 120),
|
|
'psbt_7': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('911000' * 40),
|
|
'psbt_8': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('922000' * 40),
|
|
'psbt_9': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('101000' * 40),
|
|
'psbt_10': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('201000' * 40),
|
|
'psbt_12': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('401000' * 40),
|
|
'psbt_13': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('310000' * 40),
|
|
'psbt_14': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('410000' * 40),
|
|
'psbt_15': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('510000' * 40),
|
|
'psbt_16': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('520000' * 40),
|
|
'psbt_17': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('610000' * 40),
|
|
'psbt_18': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('710000' * 40),
|
|
'psbt_19': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('810000' * 40),
|
|
'psbt_20': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('910000' * 40),
|
|
'psbt_21': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('101000' * 40),
|
|
'psbt_22': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('111000' * 40),
|
|
'psbt_23': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('121000' * 40),
|
|
'psbt_24': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('011100' * 40),
|
|
'psbt_25': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('011200' * 40),
|
|
'psbt_26': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('022200' * 40),
|
|
'signed_psbt_1': 'cHNidP8BAgQCAAAAAQMEbwAAAAEEAQpsbt' + ('718000' * 120),
|
|
'htlc_max_msat': 18446744073709552000,
|
|
}
|
|
|
|
# Used for collecting values from responses and replace them with NEW_VALUES_LIST before updating examples in schema files
|
|
REPLACE_RESPONSE_VALUES = [
|
|
{'data_keys': ['any'], 'original_value': re.compile(re.escape(CWD)), 'new_value': NEW_VALUES_LIST['root_dir']},
|
|
{'data_keys': ['any'], 'original_value': re.compile(r'/tmp/ltests-[^/]+/test_generate_examples_[^/]+/lightning-[^/]+'), 'new_value': NEW_VALUES_LIST['tmp_dir']},
|
|
{'data_keys': ['outnum', 'funding_outnum', 'vout'], 'original_value': '0', 'new_value': NEW_VALUES_LIST['str_1']},
|
|
{'data_keys': ['outnum', 'funding_outnum', 'vout'], 'original_value': 0, 'new_value': NEW_VALUES_LIST['num_1']},
|
|
{'data_keys': ['outnum', 'funding_outnum', 'vout'], 'original_value': 2, 'new_value': NEW_VALUES_LIST['num_1']},
|
|
{'data_keys': ['outnum', 'funding_outnum', 'vout'], 'original_value': 3, 'new_value': NEW_VALUES_LIST['num_1']},
|
|
{'data_keys': ['type'], 'original_value': 'unilateral', 'new_value': 'mutual'},
|
|
]
|
|
|
|
if os.path.exists(LOG_FILE):
|
|
open(LOG_FILE, 'w').close()
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class MissingExampleError(Exception):
|
|
pass
|
|
|
|
|
|
def update_list_responses(data, list_key=None, slice_upto=5, update_func=None, sort=False, sort_key=None):
|
|
"""Update responses received from various list rpcs to limit the number of items in the list, sort the list and update the values in the list"""
|
|
if list_key is not None:
|
|
if isinstance(data[list_key], list):
|
|
data[list_key] = data[list_key][0:slice_upto]
|
|
|
|
if sort:
|
|
data[list_key] = sorted(data[list_key], key=lambda x: x[sort_key]) if sort_key is not None else {k: data[list_key][k] for k in sorted(data[list_key])}
|
|
|
|
if update_func is not None and isinstance(data[list_key], list):
|
|
for i, item in enumerate(data[list_key]):
|
|
update_func(item, i)
|
|
return data
|
|
|
|
|
|
def replace_values_in_json(data, data_key):
|
|
"""Replace values in JSON data with new values before saving them in the schema files"""
|
|
if isinstance(data, dict):
|
|
return {key: replace_values_in_json(value, key) for key, value in data.items()}
|
|
elif isinstance(data, list):
|
|
for replace_value in REPLACE_RESPONSE_VALUES:
|
|
if any(item == 'any' or item == data_key for item in replace_value['data_keys']) and data == replace_value['original_value']:
|
|
data = replace_value['new_value']
|
|
return data
|
|
return [replace_values_in_json(item, 'listitem') for item in data]
|
|
elif isinstance(data, str):
|
|
for replace_value in REPLACE_RESPONSE_VALUES:
|
|
if any(item == data_key for item in replace_value['data_keys']) and data == replace_value['original_value']:
|
|
data = replace_value['new_value']
|
|
break
|
|
elif any(item == 'any' for item in replace_value['data_keys']) and isinstance(replace_value['original_value'], str) and data == replace_value['original_value']:
|
|
data = data.replace(replace_value['original_value'], replace_value['new_value'])
|
|
break
|
|
elif replace_value['data_keys'] == ['any'] and isinstance(replace_value['original_value'], re.Pattern):
|
|
if re.match(replace_value['original_value'], data):
|
|
data = replace_value['original_value'].sub(replace_value['new_value'], data)
|
|
break
|
|
return data
|
|
elif isinstance(data, (int, float)):
|
|
for replace_value in REPLACE_RESPONSE_VALUES:
|
|
if any(item == 'any' or item == data_key for item in replace_value['data_keys']) and data == replace_value['original_value']:
|
|
data = replace_value['new_value']
|
|
break
|
|
return data
|
|
else:
|
|
return data
|
|
|
|
|
|
def update_examples_in_schema_files():
|
|
"""Update examples in JSON schema files"""
|
|
try:
|
|
# For testing
|
|
if os.path.exists(TEMP_EXAMPLES_FILE):
|
|
open(TEMP_EXAMPLES_FILE, 'w').close()
|
|
with open(TEMP_EXAMPLES_FILE, 'w+', encoding='utf-8') as file:
|
|
json.dump({'new_values_list': NEW_VALUES_LIST, 'replace_response_values': REPLACE_RESPONSE_VALUES[4:], 'examples_json': EXAMPLES_JSON}, file, indent=2, ensure_ascii=False)
|
|
|
|
updated_examples = {}
|
|
for method, method_examples in EXAMPLES_JSON.items():
|
|
try:
|
|
global CWD
|
|
file_path = os.path.join(CWD, 'doc', 'schemas', f'lightning-{method}.json') if method != 'sql' else os.path.join(CWD, 'doc', 'schemas', f'lightning-{method}-template.json')
|
|
logger.info(f'Updating examples for {method} in file {file_path}')
|
|
with open(file_path, 'r+', encoding='utf-8') as file:
|
|
data = json.load(file)
|
|
updated_examples[method] = replace_values_in_json(method_examples, 'examples')['examples']
|
|
data['examples'] = updated_examples[method]
|
|
file.seek(0)
|
|
json.dump(data, file, indent=2, ensure_ascii=False)
|
|
file.write('\n')
|
|
file.truncate()
|
|
except FileNotFoundError as fnf_error:
|
|
logger.error(f'File not found error {fnf_error} for {file_path}')
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f'Error saving example in file {file_path}: {e}')
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f'Error updating examples in schema files: {e}')
|
|
raise
|
|
|
|
# For testing
|
|
if os.path.exists(TEMP_EXAMPLES_FILE):
|
|
open(TEMP_EXAMPLES_FILE, 'w').close()
|
|
with open(TEMP_EXAMPLES_FILE, 'w+', encoding='utf-8') as file:
|
|
json.dump({'new_values_list': NEW_VALUES_LIST, 'replace_response_values': REPLACE_RESPONSE_VALUES[4:], 'examples_json': EXAMPLES_JSON, 'updated_examples_json': updated_examples}, file, indent=2, ensure_ascii=False)
|
|
|
|
logger.info(f'Updated All Examples in Schema Files!')
|
|
return None
|
|
|
|
|
|
def update_example(node, method, params, response=None, description=None):
|
|
"""Add example request, response and other details in json array for future use"""
|
|
method_examples = EXAMPLES_JSON.get(method, {'examples': []})
|
|
method_id = len(method_examples['examples']) + 1
|
|
req = {
|
|
'id': f'example:{method}#{method_id}',
|
|
'method': method,
|
|
'params': params
|
|
}
|
|
logger.info(f'Method \'{method}\', Params {params}')
|
|
# Execute the RPC call and get the response
|
|
if response is None:
|
|
response = node.rpc.call(method, params)
|
|
logger.info(f'{method} response: {response}')
|
|
# Return response without updating the file because user doesn't want to update the example
|
|
# Executing the method and returning the response is useful for further example updates
|
|
if method not in REGENERATING_RPCS:
|
|
return response
|
|
else:
|
|
method_examples['examples'].append({'request': req, 'response': response} if description is None else {'description': description, 'request': req, 'response': response})
|
|
EXAMPLES_JSON[method] = method_examples
|
|
logger.info(f'Updated {method}#{method_id} example json')
|
|
return response
|
|
|
|
|
|
def setup_test_nodes(node_factory, bitcoind):
|
|
"""Sets up six test nodes for various transaction scenarios:
|
|
l1, l2, l3 for transactions and forwards
|
|
l4 for complex transactions (sendpayment, keysend, renepay)
|
|
l5 for keysend with routehints and channel backup & recovery
|
|
l5, l6 for backup and recovery
|
|
l7, l8 for splicing (added later)
|
|
l9, l10 for low level fundchannel examples (added later)
|
|
l11, l12 for low level openchannel examples (added later)
|
|
l13 for recover (added later)
|
|
l1->l2, l2->l3, l3->l4, l2->l5 (unannounced), l9->l10, l11->l12
|
|
l1.info['id']: 0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518
|
|
l2.info['id']: 022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59
|
|
l3.info['id']: 035d2b1192dfba134e10e540875d366ebc8bc353d5aa766b80c090b39c3a5d885d
|
|
l4.info['id']: 0382ce59ebf18be7d84677c2e35f23294b9992ceca95491fcf8a56c6cb2d9de199
|
|
l5.info['id']: 032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e
|
|
l6.info['id']: 0265b6ab5ec860cd257865d61ef0bbf5b3339c36cbda8b26b74e7f1dca490b6518
|
|
"""
|
|
try:
|
|
global FUND_WALLET_AMOUNT_SAT, FUND_CHANNEL_AMOUNT_SAT
|
|
options = [
|
|
{
|
|
'experimental-dual-fund': None,
|
|
'may_reconnect': True,
|
|
'dev-hsmd-no-preapprove-check': None,
|
|
'dev-no-plugin-checksum': None,
|
|
'dev-no-version-checks': None,
|
|
'allow-deprecated-apis': True,
|
|
'allow_bad_gossip': True,
|
|
'log-level': 'debug',
|
|
'broken_log': '.*',
|
|
'dev-bitcoind-poll': 3, # Default 1; increased to avoid rpc failures
|
|
}.copy()
|
|
for i in range(6)
|
|
]
|
|
l1, l2, l3, l4, l5, l6 = node_factory.get_nodes(6, opts=options)
|
|
# Upgrade wallet
|
|
# Write the data/p2sh_wallet_hsm_secret to the hsm_path, so node can spend funds at p2sh_wrapped_addr
|
|
p2sh_wrapped_addr = '2N2V4ee2vMkiXe5FSkRqFjQhiS9hKqNytv3'
|
|
update_example(node=l1, method='upgradewallet', params={})
|
|
txid = bitcoind.rpc.sendtoaddress(p2sh_wrapped_addr, 20000000 / 10 ** 8)
|
|
bitcoind.generate_block(1)
|
|
l1.daemon.wait_for_log('Owning output .* txid {} CONFIRMED'.format(txid))
|
|
# Doing it with 'reserved ok' should have 1. We use a big feerate so we can get over the RBF hump
|
|
upgrade_res2 = update_example(node=l1, method='upgradewallet', params={'feerate': 'urgent', 'reservedok': True})
|
|
|
|
# Fund node wallets for further transactions
|
|
fund_nodes = [l1, l2, l3, l4, l5]
|
|
for node in fund_nodes:
|
|
node.fundwallet(FUND_WALLET_AMOUNT_SAT)
|
|
# Connect nodes and fund channels
|
|
getinfo_res2 = update_example(node=l2, method='getinfo', params={})
|
|
update_example(node=l1, method='connect', params={'id': l2.info['id'], 'host': 'localhost', 'port': l2.daemon.port})
|
|
update_example(node=l2, method='connect', params={'id': l3.info['id'], 'host': 'localhost', 'port': l3.daemon.port})
|
|
l3.rpc.connect(l4.info['id'], 'localhost', l4.port)
|
|
l2.rpc.connect(l5.info['id'], 'localhost', l5.port)
|
|
c12, c12res = l1.fundchannel(l2, FUND_CHANNEL_AMOUNT_SAT)
|
|
c23, c23res = l2.fundchannel(l3, FUND_CHANNEL_AMOUNT_SAT)
|
|
c34, c34res = l3.fundchannel(l4, FUND_CHANNEL_AMOUNT_SAT)
|
|
c25, c25res = l2.fundchannel(l5, announce_channel=False)
|
|
mine_funding_to_announce(bitcoind, [l1, l2, l3, l4])
|
|
l1.wait_channel_active(c12)
|
|
l1.wait_channel_active(c23)
|
|
l1.wait_channel_active(c34)
|
|
# Balance these newly opened channels
|
|
l1.rpc.pay(l2.rpc.invoice('500000sat', 'lbl balance l1 to l2', 'description send some sats l1 to l2')['bolt11'])
|
|
l2.rpc.pay(l3.rpc.invoice('500000sat', 'lbl balance l2 to l3', 'description send some sats l2 to l3')['bolt11'])
|
|
l2.rpc.pay(l5.rpc.invoice('500000sat', 'lbl balance l2 to l5', 'description send some sats l2 to l5')['bolt11'])
|
|
l3.rpc.pay(l4.rpc.invoice('500000sat', 'lbl balance l3 to l4', 'description send some sats l3 to l4')['bolt11'])
|
|
REPLACE_RESPONSE_VALUES.extend([
|
|
{'data_keys': ['any', 'id', 'pubkey', 'destination'], 'original_value': l1.info['id'], 'new_value': NEW_VALUES_LIST['l1_id']},
|
|
{'data_keys': ['any', 'id', 'pubkey', 'destination'], 'original_value': l2.info['id'], 'new_value': NEW_VALUES_LIST['l2_id']},
|
|
{'data_keys': ['any', 'id', 'pubkey', 'destination'], 'original_value': l3.info['id'], 'new_value': NEW_VALUES_LIST['l3_id']},
|
|
{'data_keys': ['any', 'id', 'pubkey', 'destination'], 'original_value': l4.info['id'], 'new_value': NEW_VALUES_LIST['l4_id']},
|
|
{'data_keys': ['any', 'id', 'pubkey', 'destination'], 'original_value': l5.info['id'], 'new_value': NEW_VALUES_LIST['l5_id']},
|
|
{'data_keys': ['alias'], 'original_value': l1.info['alias'], 'new_value': NEW_VALUES_LIST['l1_alias']},
|
|
{'data_keys': ['netaddr'], 'original_value': [f'127.0.0.1:{l1.info["binding"][0]["port"]}'], 'new_value': [NEW_VALUES_LIST['l1_addr']]},
|
|
{'data_keys': ['alias'], 'original_value': l2.info['alias'], 'new_value': NEW_VALUES_LIST['l2_alias']},
|
|
{'data_keys': ['port'], 'original_value': l2.info['binding'][0]['port'], 'new_value': NEW_VALUES_LIST['l2_port']},
|
|
{'data_keys': ['netaddr'], 'original_value': [f'127.0.0.1:{l2.info["binding"][0]["port"]}'], 'new_value': [NEW_VALUES_LIST['l2_addr']]},
|
|
{'data_keys': ['version'], 'original_value': getinfo_res2['version'], 'new_value': CLN_VERSION},
|
|
{'data_keys': ['blockheight'], 'original_value': getinfo_res2['blockheight'], 'new_value': NEW_VALUES_LIST['blockheight_110']},
|
|
{'data_keys': ['alias'], 'original_value': l3.info['alias'], 'new_value': NEW_VALUES_LIST['l3_alias']},
|
|
{'data_keys': ['port'], 'original_value': l3.info['binding'][0]['port'], 'new_value': NEW_VALUES_LIST['l3_port']},
|
|
{'data_keys': ['addr'], 'original_value': f'127.0.0.1:{l3.info["binding"][0]["port"]}', 'new_value': NEW_VALUES_LIST['l3_addr']},
|
|
{'data_keys': ['netaddr'], 'original_value': [f'127.0.0.1:{l3.info["binding"][0]["port"]}'], 'new_value': [NEW_VALUES_LIST['l3_addr']]},
|
|
{'data_keys': ['alias'], 'original_value': l4.info['alias'], 'new_value': NEW_VALUES_LIST['l4_alias']},
|
|
{'data_keys': ['netaddr'], 'original_value': [f'127.0.0.1:{l4.info["binding"][0]["port"]}'], 'new_value': [NEW_VALUES_LIST['l4_addr']]},
|
|
{'data_keys': ['any', 'scid', 'channel', 'short_channel_id', 'in_channel'], 'original_value': c12, 'new_value': NEW_VALUES_LIST['c12']},
|
|
{'data_keys': ['netaddr'], 'original_value': [f'127.0.0.1:{l5.info["binding"][0]["port"]}'], 'new_value': [NEW_VALUES_LIST['l5_addr']]},
|
|
{'data_keys': ['netaddr'], 'original_value': [f'127.0.0.1:{l6.info["binding"][0]["port"]}'], 'new_value': [NEW_VALUES_LIST['l6_addr']]},
|
|
{'data_keys': ['txid', 'funding_txid'], 'original_value': c12res['txid'], 'new_value': NEW_VALUES_LIST['c12_txid']},
|
|
{'data_keys': ['channel_id', 'account'], 'original_value': c12res['channel_id'], 'new_value': NEW_VALUES_LIST['c12_channel_id']},
|
|
{'data_keys': ['scid', 'channel', 'short_channel_id', 'id', 'out_channel'], 'original_value': c23, 'new_value': NEW_VALUES_LIST['c23']},
|
|
{'data_keys': ['txid'], 'original_value': c23res['txid'], 'new_value': NEW_VALUES_LIST['c23_txid']},
|
|
{'data_keys': ['channel_id', 'account', 'origin', 'originating_account'], 'original_value': c23res['channel_id'], 'new_value': NEW_VALUES_LIST['c23_channel_id']},
|
|
{'data_keys': ['scid', 'channel', 'short_channel_id'], 'original_value': c34, 'new_value': NEW_VALUES_LIST['c34']},
|
|
{'data_keys': ['txid'], 'original_value': c34res['txid'], 'new_value': NEW_VALUES_LIST['c34_txid']},
|
|
{'data_keys': ['channel_id', 'account', 'origin'], 'original_value': c34res['channel_id'], 'new_value': NEW_VALUES_LIST['c34_channel_id']},
|
|
{'data_keys': ['scid', 'channel', 'short_channel_id', 'id'], 'original_value': c25, 'new_value': NEW_VALUES_LIST['c25']},
|
|
{'data_keys': ['channel_id', 'account'], 'original_value': c25res['channel_id'], 'new_value': NEW_VALUES_LIST['c25_channel_id']},
|
|
{'data_keys': ['tx'], 'original_value': upgrade_res2['tx'], 'new_value': NEW_VALUES_LIST['upgrade_tx']},
|
|
{'data_keys': ['txid'], 'original_value': upgrade_res2['txid'], 'new_value': NEW_VALUES_LIST['upgrade_txid']},
|
|
{'data_keys': ['initialpsbt', 'psbt', 'signed_psbt'], 'original_value': upgrade_res2['psbt'], 'new_value': NEW_VALUES_LIST['upgrade_psbt_1']},
|
|
])
|
|
return l1, l2, l3, l4, l5, l6, c12, c23, c25
|
|
except Exception as e:
|
|
logger.error(f'Error in setting up nodes: {e}')
|
|
raise
|
|
|
|
|
|
def generate_transactions_examples(l1, l2, l3, l4, l5, c25, bitcoind):
|
|
"""Generate examples for various transactions and forwards"""
|
|
try:
|
|
logger.info('Simple Transactions Start...')
|
|
global FUND_CHANNEL_AMOUNT_SAT
|
|
# Simple Transactions by creating invoices, paying invoices, keysends
|
|
inv_l31 = update_example(node=l3, method='invoice', params={'amount_msat': 10**4, 'label': 'lbl_l31', 'description': 'Invoice description l31'})
|
|
route_l1_l3 = update_example(node=l1, method='getroute', params={'id': l3.info['id'], 'amount_msat': 10**4, 'riskfactor': 1})['route']
|
|
inv_l32 = update_example(node=l3, method='invoice', params={'amount_msat': '50000msat', 'label': 'lbl_l32', 'description': 'l32 description'})
|
|
update_example(node=l2, method='getroute', params={'id': l4.info['id'], 'amount_msat': 500000, 'riskfactor': 10, 'cltv': 9})['route']
|
|
sendpay_res1 = update_example(node=l1, method='sendpay', params={'route': route_l1_l3, 'payment_hash': inv_l31['payment_hash'], 'payment_secret': inv_l31['payment_secret']})
|
|
waitsendpay_res1 = update_example(node=l1, method='waitsendpay', params={'payment_hash': inv_l31['payment_hash']})
|
|
keysend_res1 = update_example(node=l1, method='keysend', params={'destination': l3.info['id'], 'amount_msat': 10000})
|
|
keysend_res2 = update_example(node=l1, method='keysend', params={'destination': l4.info['id'], 'amount_msat': 10000000, 'extratlvs': {'133773310': '68656c6c6f776f726c64', '133773312': '66696c7465726d65'}})
|
|
scid = only_one([channel for channel in l2.rpc.listpeerchannels()['channels'] if channel['peer_id'] == l3.info['id']])['alias']['remote']
|
|
routehints = [[{
|
|
'scid': scid,
|
|
'id': l2.info['id'],
|
|
'feebase': '1msat',
|
|
'feeprop': 10,
|
|
'expirydelta': 9,
|
|
}]]
|
|
example_routehints = [[{
|
|
'scid': NEW_VALUES_LIST['c23'],
|
|
'id': NEW_VALUES_LIST['l2_id'],
|
|
'feebase': '1msat',
|
|
'feeprop': 10,
|
|
'expirydelta': 9,
|
|
}]]
|
|
keysend_res3 = update_example(node=l1, method='keysend', params={'destination': l3.info['id'], 'amount_msat': 10000, 'routehints': routehints})
|
|
inv_l11 = l1.rpc.invoice('10000msat', 'lbl_l11', 'l11 description')
|
|
inv_l21 = l2.rpc.invoice('any', 'lbl_l21', 'l21 description')
|
|
inv_l22 = l2.rpc.invoice('200000msat', 'lbl_l22', 'l22 description')
|
|
inv_l33 = l3.rpc.invoice('100000msat', 'lbl_l33', 'l33 description')
|
|
inv_l34 = l3.rpc.invoice(4000, 'failed', 'failed description')
|
|
pay_res1 = update_example(node=l1, method='pay', params=[inv_l32['bolt11']])
|
|
pay_res2 = update_example(node=l2, method='pay', params={'bolt11': inv_l33['bolt11']})
|
|
|
|
inv_l41 = l4.rpc.invoice('10000msat', 'test_xpay_simple', 'test_xpay_simple bolt11')
|
|
xpay_res1 = update_example(node=l1, method='xpay', params=[inv_l41['bolt11']])
|
|
offer_l11 = l1.rpc.offer('any')
|
|
inv_l14 = l1.rpc.fetchinvoice(offer_l11['bolt12'], '1000msat')
|
|
xpay_res2 = update_example(node=l1, method='xpay', params={'invstring': inv_l14['invoice']})
|
|
|
|
update_example(node=l1, method='injectonionmessage', params={'message': '0002cb7cd2001e3c670d64135542dcefdf4a3f590eb142cee9277b317848471906caeabe4afeae7f4e31f6ca9c119b643d5369c5e55f892f205469a185f750697124a2bb7ccea1245ec12d76340bcf7371ba6d1c9ddfe09b4153fce524417c14a594fdbb5e7c698a5daffe77db946727a38711be2ecdebdd347d2a9f990810f2795b3c39b871d7c72a11534bd388ca2517630263d96d8cc72d146bae800638066175c85a8e8665160ea332ed7d27efc31c960604d61c3f83801c25cbb69ae3962c2ef13b1fa9adc8dcbe3dc8d9a5e27ff5669e076b02cafef8f2c88fc548e03642180d57606386ad6ce27640339747d40f26eb5b9e93881fc8c16d5896122032b64bb5f1e4be6f41f5fa4dbd7851989aeccd80b2d5f6f25427f171964146185a8eaa57891d91e49a4d378743231e19edd5994c3118c9a415958a5d9524a6ecc78c0205f5c0059a7fbcf1abad706a189b712476d112521c9a4650d0ff09890536acae755a2b07d00811044df28b288d3dc2d5ae3f8bf3cf7a2950e2167105dfad0fb8398ef08f36abcdb1bfd6aca3241c33810f0750f35bdfb7c60b1759275b7704ab1bc8f3ea375b3588eab10e4f948f12fe0a3c77b67bebeedbcced1de0f0715f9959e5497cda5f8f6ab76c15b3dcc99956465de1bf2855338930650f8e8e8c391d9bb8950125dd60d8289dade0556d9dc443761983e26adcc223412b756e2fd9ad64022859b6cab20e8ffc3cf39ae6045b2c3338b1145ee3719a098e58c425db764d7f9a5034dbb730c20202f79bc3c53fab78ecd530aa0e8f7698c9ea53cb96dc9c639282c362d31177c5b81979f46f2db6090b8e171db47287523f28c462e35ef489b51426387f2709c342083968153b5f8a51cd5716b38106bb0f21c5ccfc28dd7c74b71c8367ae8ca348f66a7996bbc535076a1f65d9109658ec042257ca7523488fb1807dc8bec42739ccae066739cf58083b4e2c65e52e1747a6ec2aa26338bb6f2c3195a2b160e26dec70a2cfde269fa7c10c45d346a8bcc313bb618324edadc0291d15f4dc00ca3a7ad7131045fdf6978ba52178f4699525efcb8d96561630e2f28eaa97c66c38c66301b6c6f0124b550db620b09f35b9d45d1441cab7d93be5e3c39b9becfab7f8d05dd3a7a6e27a1d3f23f1dd01e967f5206600619f75439181848f7f4148216c11314b4eaf64c28c268ad4b33ea821d57728e9a9e9e1b6c4bcf35d14958295fc5f92bd6846f33c46f5fa20f569b25bc916b94e554f27a37448f873497e13baef8c740a7587828cc4136dd21b8584e6983e376e91663f8f91559637738b400fb49940fc2df299dfd448604b63c2f5d1f1ec023636f3baf2be5730364afd38191726a7c0d9477b1f231da4d707aabc6ad8036488181dbdb16b48500f2333036629004504d3524f87ece6afb04c4ba03ea6fce069e98b1ab7bf51f237d7c0f40756744dd703c6023b6461b90730f701404e8dddfaff40a9a60e670be7729556241fc9cc8727a586e38b71616bff8772c873b37d920d51a6ad31219a24b12f268545e2cfeb9e662236ab639fd4ecf865612678471ff7b320c934a13ca1f2587fc6a90f839c3c81c0ff84b51330820431418918e8501844893b53c1e0de46d51a64cb769974a996c58ff06683ebdc46fd4bb8e857cecebab785a351c64fd486fb648d25936cb09327b70d22c243035d4343fa3d2d148e2df5cd928010e34ae42b0333e698142050d9405b39f3aa69cecf8a388afbc7f199077b911cb829480f0952966956fe57d815f0d2467f7b28af11f8820645b601c0e1ad72a4684ebc60287d23ec3502f4c65ca44f5a4a0d79e3a5718cd23e7538cb35c57673fb9a1173e5526e767768117c7fefc2e3718f44f790b27e61995fecc6aef05107e75355be301ebe1500c147bb655a159f',
|
|
'path_key': '03ccf3faa19e8d124f27d495e3359f4002a6622b9a02df9a51b609826d354cda52'})
|
|
|
|
blockheight = l1.rpc.getinfo()['blockheight']
|
|
amt = 10**3
|
|
route = l1.rpc.getroute(l4.info['id'], amt, 10)['route']
|
|
inv = l4.rpc.invoice(amt, "lbl l4", "desc l4")
|
|
first_hop = route[0]
|
|
sendonion_hops = []
|
|
example_hops = []
|
|
i = 1
|
|
for h, n in zip(route[:-1], route[1:]):
|
|
sendonion_hops.append({'pubkey': h['id'], 'payload': serialize_payload_tlv(amt, 18 + 6, n['channel'], blockheight).hex()})
|
|
example_hops.append({'pubkey': NEW_VALUES_LIST['l2_id'] if i == 1 else NEW_VALUES_LIST['l3_id'], 'payload': 'payload0' + ((str(i) + '0') * 13)})
|
|
i += 1
|
|
sendonion_hops.append({'pubkey': route[-1]['id'], 'payload': serialize_payload_final_tlv(amt, 18, amt, blockheight, inv['payment_secret']).hex()})
|
|
example_hops.append({'pubkey': NEW_VALUES_LIST['l4_id'], 'payload': 'payload0' + ((str(i) + '0') * 13)})
|
|
onion_res1 = update_example(node=l1, method='createonion', params={'hops': sendonion_hops, 'assocdata': inv['payment_hash']})
|
|
onion_res2 = update_example(node=l1, method='createonion', params={'hops': sendonion_hops, 'assocdata': inv['payment_hash'], 'session_key': '41' * 32})
|
|
sendonion_res1 = update_example(node=l1, method='sendonion', params={'onion': onion_res1['onion'], 'first_hop': first_hop, 'payment_hash': inv['payment_hash']})
|
|
|
|
# Close channels examples
|
|
close_res1 = update_example(node=l2, method='close', params={'id': l3.info['id'], 'unilateraltimeout': 1})
|
|
address_l41 = l4.rpc.newaddr()
|
|
close_res2 = update_example(node=l3, method='close', params={'id': l4.info['id'], 'destination': address_l41['bech32']})
|
|
bitcoind.generate_block(1)
|
|
sync_blockheight(bitcoind, [l1, l2, l3, l4])
|
|
|
|
# Channel 2 to 3 is closed, l1->l3 payment will fail where `failed` forward will be saved on l2
|
|
l1.rpc.sendpay(route_l1_l3, inv_l34['payment_hash'], payment_secret=inv_l34['payment_secret'])
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.waitsendpay(inv_l34['payment_hash'])
|
|
|
|
# Reopen channels for further examples
|
|
c23_2, c23res2 = l2.fundchannel(l3, FUND_CHANNEL_AMOUNT_SAT)
|
|
c34_2, c34res2 = l3.fundchannel(l4, FUND_CHANNEL_AMOUNT_SAT)
|
|
mine_funding_to_announce(bitcoind, [l3, l4])
|
|
l2.wait_channel_active(c23_2)
|
|
update_example(node=l2, method='setchannel', params={'id': c23_2, 'ignorefeelimits': True})
|
|
update_example(node=l2, method='setchannel', params={'id': c25, 'feebase': 4000, 'feeppm': 300, 'enforcedelay': 0})
|
|
|
|
# Some more invoices for signing and preapproving
|
|
inv_l12 = l1.rpc.invoice(1000, 'label inv_l12', 'description inv_l12')
|
|
inv_l24 = l2.rpc.invoice(123000, 'label inv_l24', 'description inv_l24', 3600)
|
|
inv_l25 = l2.rpc.invoice(124000, 'label inv_l25', 'description inv_l25', 3600)
|
|
inv_l26 = l2.rpc.invoice(125000, 'label inv_l26', 'description inv_l26', 3600)
|
|
signinv_res1 = update_example(node=l2, method='signinvoice', params={'invstring': inv_l12['bolt11']})
|
|
signinv_res2 = update_example(node=l3, method='signinvoice', params=[inv_l26['bolt11']])
|
|
update_example(node=l1, method='preapprovekeysend', params={'destination': l2.info['id'], 'payment_hash': '00' * 32, 'amount_msat': 1000})
|
|
update_example(node=l5, method='preapprovekeysend', params=[l5.info['id'], '01' * 32, 2000])
|
|
update_example(node=l1, method='preapproveinvoice', params={'bolt11': inv_l24['bolt11']})
|
|
update_example(node=l1, method='preapproveinvoice', params=[inv_l25['bolt11']])
|
|
inv_req = update_example(node=l2, method='invoicerequest', params={'amount': 1000000, 'description': 'Simple test'})
|
|
sendinvoice_res1 = update_example(node=l1, method='sendinvoice', params={'invreq': inv_req['bolt12'], 'label': 'test sendinvoice'})
|
|
inv_l13 = l1.rpc.invoice(amount_msat=100000, label='lbl_l13', description='l13 description', preimage='01' * 32)
|
|
createinv_res1 = update_example(node=l2, method='createinvoice', params={'invstring': inv_l13['bolt11'], 'label': 'lbl_l13', 'preimage': '01' * 32})
|
|
inv_l27 = l2.rpc.invoice(amt, 'test_injectpaymentonion1', 'test injectpaymentonion1 description')
|
|
injectpaymentonion_hops = [
|
|
{'pubkey': l1.info['id'],
|
|
'payload': serialize_payload_tlv(1000, 18 + 6, first_scid(l1, l2), blockheight).hex()},
|
|
{'pubkey': l2.info['id'],
|
|
'payload': serialize_payload_final_tlv(1000, 18, 1000, blockheight, inv_l27['payment_secret']).hex()}]
|
|
onion_res3 = l1.rpc.createonion(hops=injectpaymentonion_hops, assocdata=inv_l27['payment_hash'])
|
|
injectpaymentonion_res1 = update_example(node=l1, method='injectpaymentonion', params={
|
|
'onion': onion_res3['onion'],
|
|
'payment_hash': inv_l27['payment_hash'],
|
|
'amount_msat': 1000,
|
|
'cltv_expiry': blockheight + 18 + 6,
|
|
'partid': 1,
|
|
'groupid': 0})
|
|
REPLACE_RESPONSE_VALUES.extend([
|
|
{'data_keys': ['destination'], 'original_value': address_l41['bech32'], 'new_value': NEW_VALUES_LIST['destination_6']},
|
|
{'data_keys': ['tx'], 'original_value': close_res1['tx'], 'new_value': NEW_VALUES_LIST['close1_tx']},
|
|
{'data_keys': ['txs'], 'original_value': close_res1['txs'], 'new_value': [NEW_VALUES_LIST['close1_tx']]},
|
|
{'data_keys': ['txid', 'spending_txid'], 'original_value': close_res1['txid'], 'new_value': NEW_VALUES_LIST['close1_txid']},
|
|
{'data_keys': ['txids'], 'original_value': close_res1['txids'], 'new_value': [NEW_VALUES_LIST['close1_txid']]},
|
|
{'data_keys': ['tx'], 'original_value': close_res2['tx'], 'new_value': NEW_VALUES_LIST['close2_tx']},
|
|
{'data_keys': ['txs'], 'original_value': close_res2['txs'], 'new_value': [NEW_VALUES_LIST['close2_tx']]},
|
|
{'data_keys': ['txid'], 'original_value': close_res2['txid'], 'new_value': NEW_VALUES_LIST['close2_txid']},
|
|
{'data_keys': ['txids'], 'original_value': close_res2['txids'], 'new_value': [NEW_VALUES_LIST['close2_txid']]},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': createinv_res1['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_l21']},
|
|
{'data_keys': ['payment_hash'], 'original_value': createinv_res1['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_l21']},
|
|
{'data_keys': ['expires_at'], 'original_value': createinv_res1['expires_at'], 'new_value': NEW_VALUES_LIST['time_at_900']},
|
|
{'data_keys': ['payment_hash'], 'original_value': inv_l31['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_l31']},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': inv_l31['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_l31']},
|
|
{'data_keys': ['payment_secret'], 'original_value': inv_l31['payment_secret'], 'new_value': NEW_VALUES_LIST['payment_secret_l31']},
|
|
{'data_keys': ['expires_at'], 'original_value': inv_l31['expires_at'], 'new_value': NEW_VALUES_LIST['time_at_900']},
|
|
{'data_keys': ['payment_hash'], 'original_value': inv_l32['payment_hash'], 'new_value': 'paymenthashinvl0' + ('3200' * 12)},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': inv_l32['bolt11'], 'new_value': 'lnbcrt100n1pnt2' + ('bolt11invl032000000000' * 10)},
|
|
{'data_keys': ['payment_secret'], 'original_value': inv_l32['payment_secret'], 'new_value': 'paymentsecretinvl000' + ('3200' * 11)},
|
|
{'data_keys': ['expires_at'], 'original_value': inv_l32['expires_at'], 'new_value': NEW_VALUES_LIST['time_at_900']},
|
|
{'data_keys': ['payment_hash'], 'original_value': inv_l11['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_l11']},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': inv_l11['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_l11']},
|
|
{'data_keys': ['payment_secret'], 'original_value': inv_l11['payment_secret'], 'new_value': NEW_VALUES_LIST['payment_secret_l11']},
|
|
{'data_keys': ['expires_at'], 'original_value': inv_l11['expires_at'], 'new_value': NEW_VALUES_LIST['time_at_900']},
|
|
{'data_keys': ['payment_hash'], 'original_value': inv_l21['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_l21']},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': inv_l21['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_l21']},
|
|
{'data_keys': ['payment_hash'], 'original_value': inv_l22['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_l22']},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': inv_l22['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_l22']},
|
|
{'data_keys': ['payment_secret'], 'original_value': inv_l22['payment_secret'], 'new_value': NEW_VALUES_LIST['payment_secret_l22']},
|
|
{'data_keys': ['payment_hash'], 'original_value': inv_l33['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_l33']},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': inv_l33['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_l33']},
|
|
{'data_keys': ['payment_hash'], 'original_value': inv_l34['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_l34']},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': inv_l34['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_l34']},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': inv_l41['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_l41']},
|
|
{'data_keys': ['invstring'], 'original_value': inv_l14['invoice'], 'new_value': NEW_VALUES_LIST['invoice_3']},
|
|
{'data_keys': ['hops'], 'original_value': sendonion_hops, 'new_value': example_hops},
|
|
{'data_keys': ['any', 'assocdata'], 'original_value': inv['payment_hash'], 'new_value': NEW_VALUES_LIST['assocdata_1']},
|
|
{'data_keys': ['onion'], 'original_value': onion_res1['onion'], 'new_value': NEW_VALUES_LIST['onion_1']},
|
|
{'data_keys': ['shared_secrets'], 'original_value': onion_res1['shared_secrets'], 'new_value': NEW_VALUES_LIST['shared_secrets_1']},
|
|
{'data_keys': ['any', 'onion'], 'original_value': onion_res2['onion'], 'new_value': NEW_VALUES_LIST['onion_2']},
|
|
{'data_keys': ['shared_secrets'], 'original_value': onion_res2['shared_secrets'], 'new_value': NEW_VALUES_LIST['shared_secrets_2']},
|
|
{'data_keys': ['onion'], 'original_value': onion_res3['onion'], 'new_value': NEW_VALUES_LIST['onion_3']},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': inv_l27['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_l27']},
|
|
{'data_keys': ['payment_hash'], 'original_value': inv_l27['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_l27']},
|
|
{'data_keys': ['payment_preimage'], 'original_value': injectpaymentonion_res1['payment_preimage'], 'new_value': NEW_VALUES_LIST['payment_preimage_io_1']},
|
|
{'data_keys': ['created_at'], 'original_value': injectpaymentonion_res1['created_at'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['completed_at'], 'original_value': injectpaymentonion_res1['completed_at'], 'new_value': NEW_VALUES_LIST['time_at_900']},
|
|
{'data_keys': ['id', 'scid', 'channel', 'short_channel_id', 'out_channel'], 'original_value': c23_2, 'new_value': NEW_VALUES_LIST['c23_2']},
|
|
{'data_keys': ['txid'], 'original_value': c23res2['txid'], 'new_value': NEW_VALUES_LIST['c23_2_txid']},
|
|
{'data_keys': ['any', 'channel_id', 'account'], 'original_value': c23res2['channel_id'], 'new_value': NEW_VALUES_LIST['c23_2_channel_id']},
|
|
{'data_keys': ['scid', 'channel', 'short_channel_id'], 'original_value': c34_2, 'new_value': NEW_VALUES_LIST['c34_2']},
|
|
{'data_keys': ['txid'], 'original_value': c34res2['txid'], 'new_value': NEW_VALUES_LIST['c34_2_txid']},
|
|
{'data_keys': ['channel_id', 'account'], 'original_value': c34res2['channel_id'], 'new_value': NEW_VALUES_LIST['c34_2_channel_id']},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': inv_l12['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_l12']},
|
|
{'data_keys': ['payment_hash'], 'original_value': inv_l24['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_l24']},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': inv_l24['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_l24']},
|
|
{'data_keys': ['expires_at'], 'original_value': inv_l24['expires_at'], 'new_value': NEW_VALUES_LIST['time_at_900']},
|
|
{'data_keys': ['payment_hash'], 'original_value': inv_l25['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_l25']},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': inv_l25['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_l25']},
|
|
{'data_keys': ['payment_hash'], 'original_value': inv_l26['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_l26']},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': inv_l26['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_l26']},
|
|
{'data_keys': ['any', 'invstring', 'bolt11'], 'original_value': inv_l13['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_l13']},
|
|
{'data_keys': ['invreq_id'], 'original_value': inv_req['invreq_id'], 'new_value': NEW_VALUES_LIST['invreq_id_1']},
|
|
{'data_keys': ['any', 'bolt12', 'invreq'], 'original_value': inv_req['bolt12'], 'new_value': NEW_VALUES_LIST['bolt12_l21']},
|
|
{'data_keys': ['payment_hash'], 'original_value': keysend_res1['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_key_1']},
|
|
{'data_keys': ['created_at'], 'original_value': keysend_res1['created_at'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['payment_preimage'], 'original_value': keysend_res1['payment_preimage'], 'new_value': NEW_VALUES_LIST['payment_preimage_1']},
|
|
{'data_keys': ['payment_hash'], 'original_value': keysend_res2['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_key_2']},
|
|
{'data_keys': ['created_at'], 'original_value': keysend_res2['created_at'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['payment_preimage'], 'original_value': keysend_res2['payment_preimage'], 'new_value': NEW_VALUES_LIST['payment_preimage_2']},
|
|
{'data_keys': ['payment_hash'], 'original_value': keysend_res3['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_key_3']},
|
|
{'data_keys': ['created_at'], 'original_value': keysend_res3['created_at'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['payment_preimage'], 'original_value': keysend_res3['payment_preimage'], 'new_value': NEW_VALUES_LIST['payment_preimage_3']},
|
|
{'data_keys': ['routehints'], 'original_value': routehints, 'new_value': example_routehints},
|
|
{'data_keys': ['created_at'], 'original_value': pay_res1['created_at'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['payment_preimage'], 'original_value': pay_res1['payment_preimage'], 'new_value': NEW_VALUES_LIST['payment_preimage_ep_1']},
|
|
{'data_keys': ['created_at'], 'original_value': pay_res2['created_at'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['payment_preimage'], 'original_value': pay_res2['payment_preimage'], 'new_value': NEW_VALUES_LIST['payment_preimage_ep_2']},
|
|
{'data_keys': ['any', 'bolt12', 'invreq'], 'original_value': sendinvoice_res1['bolt12'], 'new_value': NEW_VALUES_LIST['bolt12_si_1']},
|
|
{'data_keys': ['payment_hash'], 'original_value': sendinvoice_res1['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_si_1']},
|
|
{'data_keys': ['payment_preimage'], 'original_value': sendinvoice_res1['payment_preimage'], 'new_value': NEW_VALUES_LIST['payments_preimage_i_1']},
|
|
{'data_keys': ['paid_at'], 'original_value': sendinvoice_res1['paid_at'], 'new_value': NEW_VALUES_LIST['time_at_850']},
|
|
{'data_keys': ['expires_at'], 'original_value': sendinvoice_res1['expires_at'], 'new_value': NEW_VALUES_LIST['time_at_900']},
|
|
{'data_keys': ['created_at'], 'original_value': sendonion_res1['created_at'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['created_at'], 'original_value': sendpay_res1['created_at'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': signinv_res1['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_l66']},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': signinv_res2['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_l67']},
|
|
{'data_keys': ['payment_preimage'], 'original_value': waitsendpay_res1['payment_preimage'], 'new_value': NEW_VALUES_LIST['payments_preimage_w_1']},
|
|
{'data_keys': ['created_at'], 'original_value': waitsendpay_res1['created_at'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['completed_at'], 'original_value': waitsendpay_res1['completed_at'], 'new_value': NEW_VALUES_LIST['time_at_900']},
|
|
{'data_keys': ['payment_preimage'], 'original_value': xpay_res1['payment_preimage'], 'new_value': NEW_VALUES_LIST['payment_preimage_xp_1']},
|
|
{'data_keys': ['payment_preimage'], 'original_value': xpay_res2['payment_preimage'], 'new_value': NEW_VALUES_LIST['payment_preimage_xp_2']},
|
|
])
|
|
logger.info('Simple Transactions Done!')
|
|
return c23_2, c23res2, c34_2, inv_l11, inv_l21, inv_l22, inv_l31, inv_l32, inv_l34
|
|
except Exception as e:
|
|
logger.error(f'Error in generating transactions examples: {e}')
|
|
raise
|
|
|
|
|
|
def generate_runes_examples(l1, l2, l3):
|
|
"""Covers all runes related examples"""
|
|
try:
|
|
logger.info('Runes Start...')
|
|
# Runes
|
|
trimmed_id = l1.info['id'][:20]
|
|
rune_l21 = update_example(node=l2, method='createrune', params={}, description=['This creates a fresh rune which can do anything:'])
|
|
rune_l22 = update_example(node=l2, method='createrune', params={'rune': rune_l21['rune'], 'restrictions': 'readonly'},
|
|
description=['We can add restrictions to that rune, like so:',
|
|
'',
|
|
'The `readonly` restriction is a short-cut for two restrictions:',
|
|
'',
|
|
'1: `[\'method^list\', \'method^get\', \'method=summary\']`: You may call list, get or summary.',
|
|
'',
|
|
'2: `[\'method/listdatastore\']`: But not listdatastore: that contains sensitive stuff!'])
|
|
update_example(node=l2, method='createrune', params={'rune': rune_l21['rune'], 'restrictions': [['method^list', 'method^get', 'method=summary'], ['method/listdatastore']]}, description=['We can do the same manually (readonly), like so:'])
|
|
rune_l23 = update_example(node=l2, method='createrune', params={'restrictions': [[f'id^{trimmed_id}'], ['method=listpeers']]}, description=[f'This will allow the rune to be used for id starting with {trimmed_id}, and for the method listpeers:'])
|
|
rune_l24 = update_example(node=l2, method='createrune', params={'restrictions': [['method=pay'], ['pnameamountmsat<10000']]}, description=['This will allow the rune to be used for the method pay, and for the parameter amount\\_msat to be less than 10000:'])
|
|
update_example(node=l2, method='createrune', params={'restrictions': [[f'id={l1.info["id"]}'], ['method=listpeers'], ['pnum=1'], [f'pnameid={l1.info["id"]}', f'parr0={l1.info["id"]}']]}, description=["Let's create a rune which lets a specific peer run listpeers on themselves:"])
|
|
rune_l25 = update_example(node=l2, method='createrune', params={'restrictions': [[f'id={l1.info["id"]}'], ['method=listpeers'], ['pnum=1'], [f'pnameid^{trimmed_id}', f'parr0^{trimmed_id}']]}, description=["This allows `listpeers` with 1 argument (`pnum=1`), which is either by name (`pnameid`), or position (`parr0`). We could shorten this in several ways: either allowing only positional or named parameters, or by testing the start of the parameters only. Here's an example which only checks the first 10 bytes of the `listpeers` parameter:"])
|
|
update_example(node=l2, method='createrune', params=[rune_l25['rune'], [['time<"$(($(date +%s) + 24*60*60))"', 'rate=2']]], description=["Before we give this to our peer, let's add two more restrictions: that it only be usable for 24 hours from now (`time<`), and that it can only be used twice a minute (`rate=2`). `date +%s` can give us the current time in seconds:"])
|
|
update_example(node=l2, method='createrune', params={'restrictions': [['method^list', 'method^get', 'method=summary', 'method=pay', 'method=xpay'], ['method/listdatastore'], ['method/pay', 'per=1day'], ['method/pay', 'pnameamount_msat<100000001'], ['method/xpay', 'per=1day'], ['method/xpay', 'pnameamount_msat<100000001']]},
|
|
description=['Now, let us create a rune with `read-only` restrictions, extended to only allow sending payments of `less than 100,000 sats per day` using either the `pay` or `xpay` method. Ideally, the condition would look something like:',
|
|
'',
|
|
'`[["method^list or method^get or ((method=pay or method=xpay) and per=1day and pnameamount\\_msat<100000001)"],["method/listdatastore"]]`.',
|
|
'',
|
|
'However, since brackets and AND conditions within OR are currently not supported for rune creation, we can restructure the conditions as follows:',
|
|
'',
|
|
'- method^list|method^get|method=summary|method=pay|method=xpay',
|
|
'- method/listdatastore',
|
|
'- method/pay|per=1day',
|
|
'- method/pay|pnameamount\\_msat<100000001',
|
|
'- method/xpay|per=1day',
|
|
'- method/xpay|pnameamount\\_msat<100000001'])
|
|
update_example(node=l2, method='commando-listrunes', params={'rune': rune_l23['rune']})
|
|
update_example(node=l2, method='commando-listrunes', params={})
|
|
commando_res1 = update_example(node=l1, method='commando', params={'peer_id': l2.info['id'], 'rune': rune_l21['rune'], 'method': 'newaddr', 'params': {'addresstype': 'p2tr'}})
|
|
update_example(node=l1, method='commando', params={'peer_id': l2.info['id'], 'rune': rune_l23['rune'], 'method': 'listpeers', 'params': [l3.info['id']]})
|
|
inv_l23 = l2.rpc.invoice('any', 'lbl_l23', 'l23 description')
|
|
commando_res3 = update_example(node=l1, method='commando', params={'peer_id': l2.info['id'], 'rune': rune_l24['rune'], 'method': 'pay', 'params': {'bolt11': inv_l23['bolt11'], 'amount_msat': 9900}})
|
|
update_example(node=l2, method='checkrune', params={'nodeid': l2.info['id'], 'rune': rune_l22['rune'], 'method': 'listpeers', 'params': {}})
|
|
update_example(node=l2, method='checkrune', params={'nodeid': l2.info['id'], 'rune': rune_l24['rune'], 'method': 'pay', 'params': {'amount_msat': 9999}})
|
|
showrunes_res1 = update_example(node=l2, method='showrunes', params={'rune': rune_l21['rune']})
|
|
showrunes_res2 = update_example(node=l2, method='showrunes', params={})
|
|
update_example(node=l2, method='commando-blacklist', params={'start': 1})
|
|
update_example(node=l2, method='commando-blacklist', params={'start': 2, 'end': 3})
|
|
update_example(node=l2, method='blacklistrune', params={'start': 1})
|
|
update_example(node=l2, method='blacklistrune', params={'start': 0, 'end': 2})
|
|
update_example(node=l2, method='blacklistrune', params={'start': 3, 'end': 4})
|
|
update_example(node=l2, method='blacklistrune', params={'start': 3, 'relist': True},
|
|
description=['This undoes the blacklisting of rune 3 only'])
|
|
|
|
# Commando runes
|
|
rune_l11 = update_example(node=l1, method='commando-rune', params={}, description=['This creates a fresh rune which can do anything:'])
|
|
update_example(node=l1, method='commando-rune', params={'rune': rune_l11['rune'], 'restrictions': 'readonly'},
|
|
description=['We can add restrictions to that rune, like so:',
|
|
'',
|
|
'The `readonly` restriction is a short-cut for two restrictions:',
|
|
'',
|
|
'1: `[\'method^list\', \'method^get\', \'method=summary\']`: You may call list, get or summary.',
|
|
'',
|
|
'2: `[\'method/listdatastore\']`: But not listdatastore: that contains sensitive stuff!'])
|
|
update_example(node=l1, method='commando-rune', params={'rune': rune_l11['rune'], 'restrictions': [['method^list', 'method^get', 'method=summary'], ['method/listdatastore']]}, description=['We can do the same manually (readonly), like so:'])
|
|
update_example(node=l1, method='commando-rune', params={'restrictions': [[f'id^{trimmed_id}'], ['method=listpeers']]}, description=[f'This will allow the rune to be used for id starting with {trimmed_id}, and for the method listpeers:'])
|
|
update_example(node=l1, method='commando-rune', params={'restrictions': [['method=pay'], ['pnameamountmsat<10000']]}, description=['This will allow the rune to be used for the method pay, and for the parameter amount\\_msat to be less than 10000:'])
|
|
update_example(node=l1, method='commando-rune', params={'restrictions': [[f'id={l1.info["id"]}'], ['method=listpeers'], ['pnum=1'], [f'pnameid={l1.info["id"]}', f'parr0={l1.info["id"]}']]}, description=["Let's create a rune which lets a specific peer run listpeers on themselves:"])
|
|
rune_l15 = update_example(node=l1, method='commando-rune', params={'restrictions': [[f'id={l1.info["id"]}'], ['method=listpeers'], ['pnum=1'], [f'pnameid^{trimmed_id}', f'parr0^{trimmed_id}']]}, description=["This allows `listpeers` with 1 argument (`pnum=1`), which is either by name (`pnameid`), or position (`parr0`). We could shorten this in several ways: either allowing only positional or named parameters, or by testing the start of the parameters only. Here's an example which only checks the first 10 bytes of the `listpeers` parameter:"])
|
|
update_example(node=l1, method='commando-rune', params=[rune_l15['rune'], [['time<"$(($(date +%s) + 24*60*60))"', 'rate=2']]], description=["Before we give this to our peer, let's add two more restrictions: that it only be usable for 24 hours from now (`time<`), and that it can only be used twice a minute (`rate=2`). `date +%s` can give us the current time in seconds:"])
|
|
update_example(node=l1, method='commando-rune', params={'restrictions': [['method^list', 'method^get', 'method=summary', 'method=pay', 'method=xpay'], ['method/listdatastore'], ['method/pay', 'per=1day'], ['method/pay', 'pnameamount_msat<100000001'], ['method/xpay', 'per=1day'], ['method/xpay', 'pnameamount_msat<100000001']]},
|
|
description=['Now, let us create a rune with `read-only` restrictions, extended to only allow sending payments of `less than 100,000 sats per day` using either the `pay` or `xpay` method. Ideally, the condition would look something like:',
|
|
'',
|
|
'`[["method^list or method^get or ((method=pay or method=xpay) and per=1day and pnameamount\\_msat<100000001)"],["method/listdatastore"]]`.',
|
|
'',
|
|
'However, since brackets and AND conditions within OR are currently not supported for rune creation, we can restructure the conditions as follows:',
|
|
'',
|
|
'- method^list|method^get|method=summary|method=pay|method=xpay',
|
|
'- method/listdatastore',
|
|
'- method/pay|per=1day',
|
|
'- method/pay|pnameamount\\_msat<100000001',
|
|
'- method/xpay|per=1day',
|
|
'- method/xpay|pnameamount\\_msat<100000001'])
|
|
REPLACE_RESPONSE_VALUES.extend([
|
|
{'data_keys': ['last_used'], 'original_value': showrunes_res1['runes'][0]['last_used'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['last_used'], 'original_value': showrunes_res2['runes'][1]['last_used'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['last_used'], 'original_value': showrunes_res2['runes'][2]['last_used'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': inv_l23['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_l23']},
|
|
{'data_keys': ['p2tr'], 'original_value': commando_res1['p2tr'], 'new_value': NEW_VALUES_LIST['destination_7']},
|
|
{'data_keys': ['created_at'], 'original_value': commando_res3['created_at'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['payment_hash'], 'original_value': commando_res3['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_cmd_pay_1']},
|
|
{'data_keys': ['payment_preimage'], 'original_value': commando_res3['payment_preimage'], 'new_value': NEW_VALUES_LIST['payment_preimage_cmd_1']},
|
|
])
|
|
logger.info('Runes Done!')
|
|
return rune_l21
|
|
except Exception as e:
|
|
logger.error(f'Error in generating runes examples: {e}')
|
|
raise
|
|
|
|
|
|
def generate_datastore_examples(l2):
|
|
"""Covers all datastore related examples"""
|
|
try:
|
|
logger.info('Datastore Start...')
|
|
l2.rpc.datastore(key='somekey', hex='61', mode='create-or-append')
|
|
l2.rpc.datastore(key=['test', 'name'], string='saving data to the store', mode='must-create')
|
|
update_example(node=l2, method='datastore', params={'key': ['employee', 'index'], 'string': 'saving employee keys to the store', 'mode': 'must-create'})
|
|
update_example(node=l2, method='datastore', params={'key': 'otherkey', 'string': 'other', 'mode': 'must-create'})
|
|
update_example(node=l2, method='datastore', params={'key': 'otherkey', 'string': ' key: text to be appended to the otherkey', 'mode': 'must-append', 'generation': 0})
|
|
update_example(node=l2, method='datastoreusage', params={})
|
|
update_example(node=l2, method='datastoreusage', params={'key': ['test', 'name']})
|
|
update_example(node=l2, method='datastoreusage', params={'key': 'otherkey'})
|
|
update_example(node=l2, method='deldatastore', params={'key': ['test', 'name']})
|
|
update_example(node=l2, method='deldatastore', params={'key': 'otherkey', 'generation': 1})
|
|
logger.info('Datastore Done!')
|
|
except Exception as e:
|
|
logger.error(f'Error in generating datastore examples: {e}')
|
|
raise
|
|
|
|
|
|
def generate_bookkeeper_examples(l2, l3, c23_2_chan_id):
|
|
"""Generates all bookkeeper rpc examples"""
|
|
try:
|
|
logger.info('Bookkeeper Start...')
|
|
update_example(node=l2, method='funderupdate', params={})
|
|
update_example(node=l2, method='funderupdate', params={'policy': 'fixed', 'policy_mod': '50000sat', 'min_their_funding_msat': 1000, 'per_channel_min_msat': '1000sat', 'per_channel_max_msat': '500000sat', 'fund_probability': 100, 'fuzz_percent': 0, 'leases_only': False})
|
|
bkprinspect_res1 = update_example(node=l2, method='bkpr-inspect', params={'account': c23_2_chan_id})
|
|
update_example(node=l2, method='bkpr-dumpincomecsv', params=['koinly', 'koinly.csv'])
|
|
bkpr_channelsapy_res1 = l2.rpc.bkpr_channelsapy()
|
|
fields = [
|
|
('utilization_out', '3{}.7060%'),
|
|
('utilization_out_initial', '5{}.5591%'),
|
|
('utilization_in', '1{}.0027%'),
|
|
('utilization_in_initial', '5{}.0081%'),
|
|
('apy_out', '0.008{}%'),
|
|
('apy_out_initial', '0.012{}%'),
|
|
('apy_in', '0.008{}%'),
|
|
('apy_in_initial', '0.025{}%'),
|
|
('apy_total', '0.016{}%'),
|
|
('apy_total_initial', '0.016{}%'),
|
|
]
|
|
for i, channel in enumerate(bkpr_channelsapy_res1['channels_apy']):
|
|
for key, pattern in fields:
|
|
if key in channel:
|
|
channel[key] = pattern.format(i)
|
|
update_example(node=l2, method='bkpr-channelsapy', params={}, response=bkpr_channelsapy_res1)
|
|
|
|
# listincome and editing descriptions
|
|
listincome_result = l3.rpc.bkpr_listincome(consolidate_fees=False)
|
|
invoice = next((event for event in listincome_result['income_events'] if 'payment_id' in event), None)
|
|
utxo_event = next((event for event in listincome_result['income_events'] if 'outpoint' in event), None)
|
|
update_example(node=l3, method='bkpr-editdescriptionbypaymentid', params={'payment_id': invoice['payment_id'], 'description': 'edited invoice description from description send some sats l2 to l3'})
|
|
# Try to edit a payment_id that does not exist
|
|
update_example(node=l3, method='bkpr-editdescriptionbypaymentid', params={'payment_id': 'c000' + ('01' * 30), 'description': 'edited invoice description for non existing payment id'})
|
|
editdescriptionbyoutpoint_res1 = update_example(node=l3, method='bkpr-editdescriptionbyoutpoint', params={'outpoint': utxo_event['outpoint'], 'description': 'edited utxo description'})
|
|
# Try to edit an outpoint that does not exist
|
|
update_example(node=l3, method='bkpr-editdescriptionbyoutpoint', params={'outpoint': 'abcd' + ('02' * 30) + ':1', 'description': 'edited utxo description for non existing outpoint'})
|
|
|
|
bkprlistbal_res1 = update_example(node=l3, method='bkpr-listbalances', params={})
|
|
|
|
bkprlistaccountevents_res1 = l3.rpc.bkpr_listaccountevents(c23_2_chan_id)
|
|
bkprlistaccountevents_res1['events'] = [next((event for event in bkprlistaccountevents_res1['events'] if event['tag'] == 'channel_open'), None)]
|
|
bkprlistaccountevents_res1 = update_list_responses(bkprlistaccountevents_res1, list_key='events')
|
|
update_example(node=l3, method='bkpr-listaccountevents', params=[c23_2_chan_id], response=bkprlistaccountevents_res1)
|
|
bkprlistaccountevents_res2 = l3.rpc.bkpr_listaccountevents()
|
|
external_event = None
|
|
wallet_event = None
|
|
channel_event = None
|
|
for bkprevent in bkprlistaccountevents_res2['events']:
|
|
event_seleted = None
|
|
if wallet_event is None and bkprevent['account'] == 'wallet':
|
|
bkprevent['blockheight'] = 141
|
|
wallet_event = bkprevent
|
|
event_seleted = '01'
|
|
elif external_event is None and bkprevent['account'] == 'external' and bkprevent['origin'] == next((value['original_value'] for value in REPLACE_RESPONSE_VALUES if value['new_value'] == NEW_VALUES_LIST['c34_channel_id']), None):
|
|
bkprevent['blockheight'] = 142
|
|
external_event = bkprevent
|
|
event_seleted = '02'
|
|
elif channel_event is None and bkprevent['account'] not in ['external', 'wallet']:
|
|
bkprevent['blockheight'] = 143
|
|
channel_event = bkprevent
|
|
event_seleted = '03'
|
|
if event_seleted is not None:
|
|
bkpr_new_values = [
|
|
{'data_keys': ['timestamp'], 'original_value': bkprevent['timestamp'], 'new_value': NEW_VALUES_LIST['time_at_850'] + (int(event_seleted) * 10000)},
|
|
]
|
|
if 'debit_msat' in bkprevent and bkprevent['debit_msat'] > 0:
|
|
bkpr_new_values.extend([
|
|
{'data_keys': ['debit_msat'], 'original_value': bkprevent['debit_msat'], 'new_value': 200000000000},
|
|
])
|
|
if 'txid' in bkprevent:
|
|
bkpr_new_values.extend([
|
|
{'data_keys': ['txid'], 'original_value': bkprevent['txid'], 'new_value': 'txidbk' + (event_seleted * 29)},
|
|
])
|
|
if 'outpoint' in bkprevent:
|
|
bkpr_new_values.extend([
|
|
{'data_keys': ['outpoint'], 'original_value': bkprevent['outpoint'], 'new_value': 'txidbk' + (event_seleted * 29) + ':1'},
|
|
])
|
|
if 'payment_id' in bkprevent:
|
|
bkpr_new_values.extend([
|
|
{'data_keys': ['payment_id'], 'original_value': bkprevent['payment_id'], 'new_value': 'paymentidbk0' + (event_seleted * 26)},
|
|
])
|
|
REPLACE_RESPONSE_VALUES.extend(bkpr_new_values)
|
|
if wallet_event and external_event and channel_event:
|
|
break
|
|
bkprlistaccountevents_res2['events'] = [event for event in [external_event, wallet_event, channel_event] if event is not None]
|
|
update_example(node=l3, method='bkpr-listaccountevents', params={}, response=bkprlistaccountevents_res2)
|
|
bkprlistincome_res1 = l3.rpc.bkpr_listincome(consolidate_fees=False)
|
|
bkprlistincome_res1 = update_list_responses(bkprlistincome_res1, list_key='income_events', slice_upto=4, update_func=lambda x, i: x.update({
|
|
**({'timestamp': NEW_VALUES_LIST['time_at_850'] + (i * 10000)} if 'timestamp' in x else {}),
|
|
**({'payment_id': 'paymentid000' + (f"{i:02}" * 26)} if 'payment_id' in x else {}),
|
|
**({'outpoint': 'txidbk' + (f"{i:02}" * 29) + ':1'} if 'outpoint' in x else {})}), sort=True, sort_key='tag')
|
|
update_example(node=l3, method='bkpr-listincome', params={'consolidate_fees': False}, response=bkprlistincome_res1)
|
|
bkprlistincome_res2 = l3.rpc.bkpr_listincome()
|
|
deposit_income = None
|
|
invoice_income = None
|
|
fee_income = None
|
|
for bkprincome in bkprlistincome_res2['income_events']:
|
|
income_seleted = None
|
|
if deposit_income is None and bkprincome['tag'] == 'deposit':
|
|
deposit_income = bkprincome
|
|
income_seleted = 1
|
|
elif invoice_income is None and bkprincome['tag'] == 'invoice':
|
|
invoice_income = bkprincome
|
|
income_seleted = 2
|
|
elif fee_income is None and bkprincome['tag'] == 'onchain_fee' and bkprincome['txid'] == next((value['original_value'] for value in REPLACE_RESPONSE_VALUES if value['new_value'] == NEW_VALUES_LIST['c34_2_txid']), None):
|
|
fee_income = bkprincome
|
|
income_seleted = 3
|
|
if income_seleted is not None:
|
|
REPLACE_RESPONSE_VALUES.extend([
|
|
{'data_keys': ['timestamp'], 'original_value': bkprincome['timestamp'], 'new_value': NEW_VALUES_LIST['time_at_850'] + (income_seleted * 10000)},
|
|
])
|
|
if 'debit_msat' in bkprincome and bkprincome['debit_msat'] > 0:
|
|
REPLACE_RESPONSE_VALUES.extend([
|
|
{'data_keys': ['debit_msat'], 'original_value': bkprincome['debit_msat'], 'new_value': 6960000},
|
|
])
|
|
if 'payment_id' in bkprincome:
|
|
REPLACE_RESPONSE_VALUES.extend([
|
|
{'data_keys': ['payment_id'], 'original_value': bkprincome['payment_id'], 'new_value': 'paymentid000' + (f"{income_seleted:02}" * 26)},
|
|
])
|
|
if 'outpoint' in bkprincome:
|
|
REPLACE_RESPONSE_VALUES.extend([
|
|
{'data_keys': ['outpoint'], 'original_value': bkprincome['outpoint'], 'new_value': 'txidbk' + (f"{income_seleted:02}" * 29) + ':1'},
|
|
])
|
|
if deposit_income and invoice_income and fee_income:
|
|
break
|
|
bkprlistincome_res2['income_events'] = [income for income in [deposit_income, invoice_income, fee_income] if income is not None]
|
|
update_example(node=l3, method='bkpr-listincome', params={}, response=bkprlistincome_res2)
|
|
REPLACE_RESPONSE_VALUES.extend([
|
|
{'data_keys': ['balance_msat'], 'original_value': bkprlistbal_res1['accounts'][0]['balances'][0]['balance_msat'], 'new_value': NEW_VALUES_LIST['balance_msat_1']},
|
|
{'data_keys': ['fees_paid_msat'], 'original_value': bkprinspect_res1['txs'][0]['fees_paid_msat'], 'new_value': NEW_VALUES_LIST['fees_paid_msat_1']},
|
|
{'data_keys': ['timestamp'], 'original_value': bkprlistaccountevents_res1['events'][0]['timestamp'], 'new_value': NEW_VALUES_LIST['time_at_850']},
|
|
{'data_keys': ['outpoint'], 'original_value': bkprlistaccountevents_res1['events'][0]['outpoint'], 'new_value': 'txidbk' + ('01' * 29) + ':1'},
|
|
{'data_keys': ['blockheight'], 'original_value': editdescriptionbyoutpoint_res1['updated'][0]['blockheight'], 'new_value': NEW_VALUES_LIST['blockheight_110']},
|
|
])
|
|
logger.info('Bookkeeper Done!')
|
|
except Exception as e:
|
|
logger.error(f'Error in generating bookkeeper examples: {e}')
|
|
raise
|
|
|
|
|
|
def generate_offers_renepay_examples(l1, l2, inv_l21, inv_l34):
|
|
"""Covers all offers and renepay related examples"""
|
|
try:
|
|
logger.info('Offers and Renepay Start...')
|
|
|
|
# Offers & Offers Lists
|
|
offer_l21 = update_example(node=l2, method='offer', params={'amount': '10000msat', 'description': 'Fish sale!'})
|
|
offer_l22 = update_example(node=l2, method='offer', params={'amount': '1000sat', 'description': 'Coffee', 'quantity_max': 10})
|
|
offer_l23 = l2.rpc.offer('2000sat', 'Offer to Disable')
|
|
fetchinv_res1 = update_example(node=l1, method='fetchinvoice', params={'offer': offer_l21['bolt12'], 'payer_note': 'Thanks for the fish!'})
|
|
fetchinv_res2 = update_example(node=l1, method='fetchinvoice', params={'offer': offer_l22['bolt12'], 'amount_msat': 2000000, 'quantity': 2})
|
|
update_example(node=l2, method='disableoffer', params={'offer_id': offer_l23['offer_id']})
|
|
update_example(node=l2, method='enableoffer', params={'offer_id': offer_l23['offer_id']})
|
|
|
|
# Invoice Requests
|
|
inv_req_l1_l22 = update_example(node=l2, method='invoicerequest', params={'amount': '10000sat', 'description': 'Requesting for invoice', 'issuer': 'clightning store'})
|
|
disableinv_res1 = update_example(node=l2, method='disableinvoicerequest', params={'invreq_id': inv_req_l1_l22['invreq_id']})
|
|
|
|
# Renepay
|
|
renepay_res1 = update_example(node=l1, method='renepay', params={'invstring': inv_l21['bolt11'], 'amount_msat': 400000})
|
|
renepay_res2 = update_example(node=l2, method='renepay', params={'invstring': inv_l34['bolt11']})
|
|
update_example(node=l1, method='renepaystatus', params={'invstring': inv_l21['bolt11']})
|
|
REPLACE_RESPONSE_VALUES.extend([
|
|
{'data_keys': ['offer_id'], 'original_value': offer_l21['offer_id'], 'new_value': NEW_VALUES_LIST['offerid_l21']},
|
|
{'data_keys': ['any', 'bolt12', 'invreq'], 'original_value': offer_l21['bolt12'], 'new_value': NEW_VALUES_LIST['bolt12_l21']},
|
|
{'data_keys': ['offer_id'], 'original_value': offer_l22['offer_id'], 'new_value': NEW_VALUES_LIST['offerid_l22']},
|
|
{'data_keys': ['any', 'bolt12', 'invreq'], 'original_value': offer_l22['bolt12'], 'new_value': NEW_VALUES_LIST['bolt12_l22']},
|
|
{'data_keys': ['any', 'offer_id'], 'original_value': offer_l23['offer_id'], 'new_value': NEW_VALUES_LIST['offerid_l23']},
|
|
{'data_keys': ['any', 'bolt12', 'invreq'], 'original_value': offer_l23['bolt12'], 'new_value': NEW_VALUES_LIST['bolt12_l23']},
|
|
{'data_keys': ['invreq_id'], 'original_value': inv_req_l1_l22['invreq_id'], 'new_value': NEW_VALUES_LIST['invreq_id_2']},
|
|
{'data_keys': ['any', 'bolt12', 'invreq'], 'original_value': disableinv_res1['bolt12'], 'new_value': NEW_VALUES_LIST['bolt12_l24']},
|
|
{'data_keys': ['invoice'], 'original_value': fetchinv_res1['invoice'], 'new_value': NEW_VALUES_LIST['invoice_1']},
|
|
{'data_keys': ['invoice'], 'original_value': fetchinv_res2['invoice'], 'new_value': NEW_VALUES_LIST['invoice_2']},
|
|
{'data_keys': ['created_at'], 'original_value': renepay_res1['created_at'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['payment_preimage'], 'original_value': renepay_res1['payment_preimage'], 'new_value': NEW_VALUES_LIST['payment_preimage_r_1']},
|
|
{'data_keys': ['created_at'], 'original_value': renepay_res2['created_at'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['payment_preimage'], 'original_value': renepay_res2['payment_preimage'], 'new_value': NEW_VALUES_LIST['payment_preimage_r_2']},
|
|
])
|
|
logger.info('Offers and Renepay Done!')
|
|
return offer_l23, inv_req_l1_l22
|
|
except Exception as e:
|
|
logger.error(f'Error in generating offers or renepay examples: {e}')
|
|
raise
|
|
|
|
|
|
def generate_askrene_examples(l1, l2, l3, c12, c23_2):
|
|
"""Generates askrene related examples"""
|
|
try:
|
|
logger.info('Askrene Start...')
|
|
|
|
def direction(src, dst):
|
|
if src < dst:
|
|
return 0
|
|
return 1
|
|
|
|
direction12 = direction(l1.info['id'], l2.info['id'])
|
|
direction23 = direction(l2.info['id'], l3.info['id'])
|
|
scid12dir = f'{c12}/{direction12}'
|
|
scid23dir = f'{c23_2}/{direction23}'
|
|
update_example(node=l2, method='askrene-create-layer', params={'layer': 'test_layers'})
|
|
update_example(node=l2, method='askrene-disable-node', params={'layer': 'test_layers', 'node': l1.info['id']})
|
|
update_example(node=l2, method='askrene-update-channel', params=['test_layers', '0x0x1/0'])
|
|
update_example(node=l2, method='askrene-create-channel', params={'layer': 'test_layers', 'source': l3.info['id'], 'destination': l1.info['id'], 'short_channel_id': '0x0x1', 'capacity_msat': '1000000sat'})
|
|
update_example(node=l2, method='askrene-update-channel', params={'layer': 'test_layers', 'short_channel_id_dir': '0x0x1/0', 'htlc_minimum_msat': 100, 'htlc_maximum_msat': 900000000, 'fee_base_msat': 1, 'fee_proportional_millionths': 2, 'cltv_expiry_delta': 18})
|
|
askrene_inform_channel_res1 = update_example(node=l2, method='askrene-inform-channel', params={'layer': 'test_layers', 'short_channel_id_dir': '0x0x1/1', 'amount_msat': 100000, 'inform': 'unconstrained'})
|
|
update_example(node=l2, method='askrene-bias-channel', params={'layer': 'test_layers', 'short_channel_id_dir': scid12dir, 'bias': 1})
|
|
update_example(node=l2, method='askrene-bias-channel', params=['test_layers', scid12dir, -5, 'bigger bias'])
|
|
askrene_listlayers_res1 = update_example(node=l2, method='askrene-listlayers', params=['test_layers'])
|
|
update_example(node=l2, method='askrene-listlayers', params={})
|
|
ts1 = only_one(only_one(askrene_listlayers_res1['layers'])['constraints'])['timestamp']
|
|
update_example(node=l2, method='askrene-age', params={'layer': 'test_layers', 'cutoff': ts1 + 1})
|
|
update_example(node=l2, method='askrene-remove-layer', params={'layer': 'test_layers'})
|
|
update_example(node=l1, method='getroutes', params={'source': l1.info['id'], 'destination': l3.info['id'], 'amount_msat': 1250000, 'layers': [], 'maxfee_msat': 125000, 'final_cltv': 0})
|
|
update_example(node=l1, method='askrene-reserve', params={'path': [{'short_channel_id_dir': scid12dir, 'amount_msat': 1250_000}, {'short_channel_id_dir': scid23dir, 'amount_msat': 1250_001}]})
|
|
update_example(node=l1, method='askrene-reserve', params={'path': [{'short_channel_id_dir': scid12dir, 'amount_msat': 1250_000_000_000}, {'short_channel_id_dir': scid23dir, 'amount_msat': 1250_000_000_000}]})
|
|
time.sleep(2)
|
|
askrene_listreservations_res1 = l1.rpc.askrene_listreservations()
|
|
askrene_listreservations_res1 = update_list_responses(askrene_listreservations_res1, list_key='reservations', slice_upto=5, update_func=lambda x, i: REPLACE_RESPONSE_VALUES.extend([{'data_keys': ['command_id'], 'original_value': x['command_id'], 'new_value': f'\"-c:askrene-reserve#6{(i + 1) * 2}/cln:askrene-reserve#12{(i + 1) * 2}\"'}]), sort=True, sort_key='amount_msat')
|
|
update_example(node=l1, method='askrene-listreservations', params={}, response=askrene_listreservations_res1)
|
|
update_example(node=l1, method='askrene-unreserve', params={'path': [{'short_channel_id_dir': scid12dir, 'amount_msat': 1250_000}, {'short_channel_id_dir': scid23dir, 'amount_msat': 1250_001}]})
|
|
update_example(node=l1, method='askrene-unreserve', params={'path': [{'short_channel_id_dir': scid12dir, 'amount_msat': 1250_000_000_000}, {'short_channel_id_dir': scid23dir, 'amount_msat': 1250_000_000_000}]})
|
|
REPLACE_RESPONSE_VALUES.extend([
|
|
{'data_keys': ['any', 'short_channel_id_dir'], 'original_value': scid12dir, 'new_value': f"{NEW_VALUES_LIST['c12']}/{direction12}"},
|
|
{'data_keys': ['short_channel_id_dir'], 'original_value': scid23dir, 'new_value': f"{NEW_VALUES_LIST['c23_2']}/{direction23}"},
|
|
{'data_keys': ['cutoff'], 'original_value': ts1 + 1, 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['timestamp'], 'original_value': askrene_inform_channel_res1['constraints'][0]['timestamp'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
])
|
|
logger.info('Askrene Done!')
|
|
except Exception as e:
|
|
logger.error(f'Error in generating askrene examples: {e}')
|
|
raise
|
|
|
|
|
|
def generate_wait_examples(l1, l2, bitcoind, executor):
|
|
"""Generates wait examples"""
|
|
try:
|
|
logger.info('Wait Start...')
|
|
inv1 = l2.rpc.invoice(1000, 'inv1', 'inv1')
|
|
inv2 = l2.rpc.invoice(2000, 'inv2', 'inv2')
|
|
inv3 = l2.rpc.invoice(3000, 'inv3', 'inv3')
|
|
inv4 = l2.rpc.invoice(4000, 'inv4', 'inv4')
|
|
inv5 = l2.rpc.invoice(5000, 'inv5', 'inv5')
|
|
# Wait invoice
|
|
wi3 = executor.submit(l2.rpc.waitinvoice, 'inv3')
|
|
time.sleep(1)
|
|
l1.rpc.pay(inv2['bolt11'])
|
|
time.sleep(1)
|
|
wi2res = executor.submit(l2.rpc.waitinvoice, 'inv2').result(timeout=5)
|
|
update_example(node=l2, method='waitinvoice', params={'label': 'inv2'}, response=wi2res)
|
|
|
|
l1.rpc.pay(inv3['bolt11'])
|
|
wi3res = wi3.result(timeout=5)
|
|
update_example(node=l2, method='waitinvoice', params=['inv3'], response=wi3res)
|
|
|
|
# Wait any invoice
|
|
wai = executor.submit(l2.rpc.waitanyinvoice)
|
|
time.sleep(1)
|
|
l1.rpc.pay(inv5['bolt11'])
|
|
l1.rpc.pay(inv4['bolt11'])
|
|
waires = wai.result(timeout=5)
|
|
update_example(node=l2, method='waitanyinvoice', params={}, response=waires)
|
|
pay_index = waires['pay_index']
|
|
wai_pay_index_res = executor.submit(l2.rpc.waitanyinvoice, pay_index, 0).result(timeout=5)
|
|
update_example(node=l2, method='waitanyinvoice', params={'lastpay_index': pay_index, 'timeout': 0}, response=wai_pay_index_res)
|
|
|
|
# Wait with subsystem examples
|
|
update_example(node=l2, method='wait', params={'subsystem': 'invoices', 'indexname': 'created', 'nextvalue': 0})
|
|
|
|
wspres_l1 = l1.rpc.wait(subsystem='sendpays', indexname='created', nextvalue=0)
|
|
nextvalue = int(wspres_l1['created']) + 1
|
|
wsp_created_l1 = executor.submit(l1.rpc.call, 'wait', {'subsystem': 'sendpays', 'indexname': 'created', 'nextvalue': nextvalue})
|
|
wsp_updated_l1 = executor.submit(l1.rpc.call, 'wait', {'subsystem': 'sendpays', 'indexname': 'updated', 'nextvalue': nextvalue})
|
|
time.sleep(1)
|
|
routestep = {
|
|
'amount_msat': 1000,
|
|
'id': l2.info['id'],
|
|
'delay': 5,
|
|
'channel': first_scid(l1, l2)
|
|
}
|
|
l1.rpc.sendpay([routestep], inv1['payment_hash'], payment_secret=inv1['payment_secret'])
|
|
wspc_res = wsp_created_l1.result(5)
|
|
wspu_res = wsp_updated_l1.result(5)
|
|
update_example(node=l1, method='wait', params={'subsystem': 'sendpays', 'indexname': 'created', 'nextvalue': nextvalue}, response=wspc_res)
|
|
update_example(node=l1, method='wait', params=['sendpays', 'updated', nextvalue], response=wspu_res)
|
|
|
|
# Wait blockheight
|
|
curr_blockheight = l2.rpc.getinfo()['blockheight']
|
|
if curr_blockheight < 130:
|
|
bitcoind.generate_block(130 - curr_blockheight)
|
|
sync_blockheight(bitcoind, [l2])
|
|
update_example(node=l2, method='waitblockheight', params={'blockheight': 126}, description=[f'This will return immediately since the current blockheight exceeds the requested waitblockheight.'])
|
|
wbh = executor.submit(l2.rpc.waitblockheight, curr_blockheight + 1, 600)
|
|
bitcoind.generate_block(1)
|
|
sync_blockheight(bitcoind, [l2])
|
|
wbhres = wbh.result(5)
|
|
update_example(node=l2, method='waitblockheight', params={'blockheight': curr_blockheight + 1, 'timeout': 600}, response=wbhres, description=[f'This will return after the next block is mined because requested waitblockheight is one block higher than the current blockheight.'])
|
|
REPLACE_RESPONSE_VALUES.extend([
|
|
{'data_keys': ['payment_hash'], 'original_value': wspc_res['details']['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_wspc_1']},
|
|
{'data_keys': ['paid_at'], 'original_value': waires['paid_at'], 'new_value': NEW_VALUES_LIST['time_at_850']},
|
|
{'data_keys': ['expires_at'], 'original_value': waires['expires_at'], 'new_value': NEW_VALUES_LIST['time_at_900']},
|
|
{'data_keys': ['paid_at'], 'original_value': wai_pay_index_res['paid_at'], 'new_value': NEW_VALUES_LIST['time_at_850']},
|
|
{'data_keys': ['expires_at'], 'original_value': wai_pay_index_res['expires_at'], 'new_value': NEW_VALUES_LIST['time_at_900']},
|
|
{'data_keys': ['bolt11'], 'original_value': wi2res['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_wt_1']},
|
|
{'data_keys': ['payment_hash'], 'original_value': wi2res['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_winv_1']},
|
|
{'data_keys': ['payment_preimage'], 'original_value': wi2res['payment_preimage'], 'new_value': NEW_VALUES_LIST['payment_preimage_wi_1']},
|
|
{'data_keys': ['paid_at'], 'original_value': wi2res['paid_at'], 'new_value': NEW_VALUES_LIST['time_at_850']},
|
|
{'data_keys': ['expires_at'], 'original_value': wi2res['expires_at'], 'new_value': NEW_VALUES_LIST['time_at_900']},
|
|
{'data_keys': ['bolt11'], 'original_value': wi3res['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_wt_2']},
|
|
{'data_keys': ['payment_hash'], 'original_value': wi3res['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_winv_2']},
|
|
{'data_keys': ['payment_preimage'], 'original_value': wi3res['payment_preimage'], 'new_value': NEW_VALUES_LIST['payment_preimage_wi_2']},
|
|
{'data_keys': ['paid_at'], 'original_value': wi3res['paid_at'], 'new_value': NEW_VALUES_LIST['time_at_850']},
|
|
{'data_keys': ['expires_at'], 'original_value': wi3res['expires_at'], 'new_value': NEW_VALUES_LIST['time_at_900']},
|
|
])
|
|
logger.info('Wait Done!')
|
|
except Exception as e:
|
|
logger.error(f'Error in generating wait examples: {e}')
|
|
raise
|
|
|
|
|
|
def generate_utils_examples(l1, l2, l3, l4, l5, l6, c23_2, c34_2, inv_l11, inv_l22, rune_l21, bitcoind):
|
|
"""Generates other utilities examples"""
|
|
try:
|
|
logger.info('General Utils Start...')
|
|
global CWD, FUND_CHANNEL_AMOUNT_SAT
|
|
update_example(node=l2, method='batching', params={'enable': True})
|
|
update_example(node=l2, method='ping', params={'id': l1.info['id'], 'len': 128, 'pongbytes': 128})
|
|
update_example(node=l2, method='ping', params={'id': l3.info['id'], 'len': 1000, 'pongbytes': 65535})
|
|
update_example(node=l2, method='help', params={'command': 'pay'})
|
|
update_example(node=l2, method='help', params={'command': 'dev'})
|
|
update_example(node=l2, method='setconfig', params=['autoclean-expiredinvoices-age', 300])
|
|
update_example(node=l2, method='setconfig', params={'config': 'min-capacity-sat', 'val': 500000})
|
|
update_example(node=l2, method='addgossip', params={'message': '010078c3314666731e339c0b8434f7824797a084ed7ca3655991a672da068e2c44cb53b57b53a296c133bc879109a8931dc31e6913a4bda3d58559b99b95663e6d52775579447ef5526300e1bb89bc6af8557aa1c3810a91814eafad6d103f43182e17b16644cb38c1d58a8edd094303959a9f1f9d42ff6c32a21f9c118531f512c8679cabaccc6e39dbd95a4dac90e75a258893c3aa3f733d1b8890174d5ddea8003cadffe557773c54d2c07ca1d535c4bf85885f879ae466c16a516e8ffcfec1740e3f5c98ca9ce13f452e867befef5517f306ed6aa5119b79059bcc6f68f329986b665d16de7bc7df64e3537504c91eeabe0e59d3a2b68e4216ead2b0f6e3ef7c000006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f0000670000010000022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d590266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c0351802e3bd38009866c9da8ec4aa99cc4ea9c6c0dd46df15c61ef0ce1f271291714e5702324266de8403b3ab157a09f1f784d587af61831c998c151bcc21bb74c2b2314b'})
|
|
update_example(node=l2, method='addgossip', params={'message': '0102420526c8eb62ec6999bbee5f1de4841cab734374ec642b7deeb0259e76220bf82e97a241c907d5ff52019655f7f9a614c285bb35690f3a1a2b928d7b2349a79e06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f000067000001000065b32a0e010100060000000000000000000000010000000a000000003b023380'})
|
|
update_example(node=l2, method='deprecations', params={'enable': True})
|
|
update_example(node=l2, method='deprecations', params={'enable': False})
|
|
getlog_res1 = l2.rpc.getlog(level='unusual')
|
|
getlog_res1['log'] = getlog_res1['log'][0:5]
|
|
update_example(node=l2, method='getlog', params={'level': 'unusual'}, response=getlog_res1)
|
|
update_example(node=l2, method='notifications', params={'enable': True})
|
|
update_example(node=l2, method='notifications', params={'enable': False})
|
|
update_example(node=l2, method='check', params={'command_to_check': 'sendpay', 'route': [{'amount_msat': 1011, 'id': l3.info['id'], 'delay': 20, 'channel': c23_2}, {'amount_msat': 1000, 'id': l4.info['id'], 'delay': 10, 'channel': c34_2}], 'payment_hash': '0000000000000000000000000000000000000000000000000000000000000000'})
|
|
update_example(node=l2, method='check', params={'command_to_check': 'dev', 'subcommand': 'slowcmd', 'msec': 1000})
|
|
update_example(node=l6, method='check', params={'command_to_check': 'recover', 'hsmsecret': '6c696768746e696e672d31000000000000000000000000000000000000000000'})
|
|
update_example(node=l2, method='plugin', params={'subcommand': 'start', 'plugin': os.path.join(CWD, 'tests/plugins/allow_even_msgs.py')})
|
|
update_example(node=l2, method='plugin', params={'subcommand': 'stop', 'plugin': os.path.join(CWD, 'tests/plugins/allow_even_msgs.py')})
|
|
update_example(node=l2, method='plugin', params=['list'])
|
|
update_example(node=l2, method='sendcustommsg', params={'node_id': l3.info['id'], 'msg': '77770012'})
|
|
|
|
# Wallet Utils
|
|
address_l21 = update_example(node=l2, method='newaddr', params={})
|
|
address_l22 = update_example(node=l2, method='newaddr', params={'addresstype': 'p2tr'})
|
|
withdraw_l21 = update_example(node=l2, method='withdraw', params={'destination': address_l21['bech32'], 'satoshi': 555555})
|
|
|
|
bitcoind.generate_block(4, wait_for_mempool=[withdraw_l21['txid']])
|
|
sync_blockheight(bitcoind, [l2])
|
|
|
|
funds_l2 = l2.rpc.listfunds()
|
|
utxos = [f"{funds_l2['outputs'][2]['txid']}:{funds_l2['outputs'][2]['output']}"]
|
|
example_utxos = ['utxo' + ('02' * 30) + ':1']
|
|
withdraw_l22 = update_example(node=l2, method='withdraw', params={'destination': address_l22['p2tr'], 'satoshi': 'all', 'feerate': '20000perkb', 'minconf': 0, 'utxos': utxos})
|
|
bitcoind.generate_block(4, wait_for_mempool=[withdraw_l22['txid']])
|
|
multiwithdraw_res1 = update_example(node=l2, method='multiwithdraw', params={'outputs': [{l1.rpc.newaddr()['bech32']: '2222000msat'}, {l1.rpc.newaddr()['bech32']: '3333000msat'}]})
|
|
multiwithdraw_res2 = update_example(node=l2, method='multiwithdraw', params={'outputs': [{l1.rpc.newaddr('p2tr')['p2tr']: 1000}, {l1.rpc.newaddr()['bech32']: 1000}, {l2.rpc.newaddr()['bech32']: 1000}, {l3.rpc.newaddr()['bech32']: 1000}, {l3.rpc.newaddr()['bech32']: 1000}, {l4.rpc.newaddr('p2tr')['p2tr']: 1000}, {l1.rpc.newaddr()['bech32']: 1000}]})
|
|
l2.rpc.connect(l4.info['id'], 'localhost', l4.port)
|
|
l2.rpc.connect(l5.info['id'], 'localhost', l5.port)
|
|
update_example(node=l2, method='disconnect', params={'id': l4.info['id'], 'force': False})
|
|
update_example(node=l2, method='disconnect', params={'id': l5.info['id'], 'force': True})
|
|
update_example(node=l2, method='parsefeerate', params=['unilateral_close'])
|
|
update_example(node=l2, method='parsefeerate', params=['9999perkw'])
|
|
update_example(node=l2, method='parsefeerate', params=[10000])
|
|
update_example(node=l2, method='parsefeerate', params=['urgent'])
|
|
update_example(node=l2, method='feerates', params={'style': 'perkw'})
|
|
update_example(node=l2, method='feerates', params={'style': 'perkb'})
|
|
update_example(node=l2, method='signmessage', params={'message': 'this is a test!'})
|
|
update_example(node=l2, method='signmessage', params={'message': 'message for you'})
|
|
update_example(node=l2, method='checkmessage', params={'message': 'testcase to check new rpc error', 'zbase': 'd66bqz3qsku5fxtqsi37j11pci47ydxa95iusphutggz9ezaxt56neh77kxe5hyr41kwgkncgiu94p9ecxiexgpgsz8daoq4tw8kj8yx', 'pubkey': '03be3b0e9992153b1d5a6e1623670b6c3663f72ce6cf2e0dd39c0a373a7de5a3b7'})
|
|
update_example(node=l2, method='checkmessage', params={'message': 'this is a test!', 'zbase': 'd6tqaeuonjhi98mmont9m4wag7gg4krg1f4txonug3h31e9h6p6k6nbwjondnj46dkyausobstnk7fhyy998bhgc1yr98dfmhb4k54d7'})
|
|
decodepay_res1 = update_example(node=l2, method='decodepay', params={'bolt11': inv_l11['bolt11']})
|
|
update_example(node=l2, method='decode', params=[rune_l21['rune']])
|
|
decode_res2 = update_example(node=l2, method='decode', params=[inv_l22['bolt11']])
|
|
|
|
# PSBT
|
|
amount1 = 1000000
|
|
amount2 = 3333333
|
|
psbtoutput_res1 = update_example(node=l1, method='addpsbtoutput', params={'satoshi': amount1, 'locktime': 111}, description=[f'Here is a command to make a PSBT with a {amount1:,} sat output that leads to the on-chain wallet:'])
|
|
update_example(node=l1, method='setpsbtversion', params={'psbt': psbtoutput_res1['psbt'], 'version': 0})
|
|
psbtoutput_res2 = l1.rpc.addpsbtoutput(amount2, psbtoutput_res1['psbt'])
|
|
update_example(node=l1, method='addpsbtoutput', params=[amount2, psbtoutput_res2['psbt']], response=psbtoutput_res2)
|
|
dest = l1.rpc.newaddr('p2tr')['p2tr']
|
|
psbtoutput_res3 = update_example(node=l1, method='addpsbtoutput', params={'satoshi': amount2, 'initialpsbt': psbtoutput_res2['psbt'], 'destination': dest})
|
|
l1.rpc.addpsbtoutput(amount2, psbtoutput_res2['psbt'], None, dest)
|
|
update_example(node=l1, method='setpsbtversion', params=[psbtoutput_res2['psbt'], 2])
|
|
|
|
out_total = Millisatoshi(3000000 * 1000)
|
|
funding = l1.rpc.fundpsbt(satoshi=out_total, feerate=7500, startweight=42)
|
|
psbt = bitcoind.rpc.decodepsbt(funding['psbt'])
|
|
saved_input = psbt['tx']['vin'][0]
|
|
l1.rpc.unreserveinputs(funding['psbt'])
|
|
psbt = bitcoind.rpc.createpsbt([{'txid': saved_input['txid'],
|
|
'vout': saved_input['vout']}], [])
|
|
out_1_ms = Millisatoshi(funding['excess_msat'])
|
|
output_psbt = bitcoind.rpc.createpsbt([], [{'bcrt1qeyyk6sl5pr49ycpqyckvmttus5ttj25pd0zpvg': float((out_total + out_1_ms).to_btc())}])
|
|
fullpsbt = bitcoind.rpc.joinpsbts([funding['psbt'], output_psbt])
|
|
l1.rpc.reserveinputs(fullpsbt)
|
|
signed_psbt = l1.rpc.signpsbt(fullpsbt)['signed_psbt']
|
|
sendpsbt_res1 = update_example(node=l1, method='sendpsbt', params={'psbt': signed_psbt})
|
|
|
|
# SQL
|
|
update_example(node=l1, method='sql', params={'query': 'SELECT id FROM peers'}, description=['A simple peers selection query:'])
|
|
update_example(node=l1, method='sql', params=[f"SELECT label, description, status FROM invoices WHERE label='label inv_l12'"], description=["A statement containing `=` needs `-o` in shell:"])
|
|
sql_res3 = l1.rpc.sql(f"SELECT nodeid FROM nodes WHERE nodeid != x'{l3.info['id']}'")
|
|
update_example(node=l1, method='sql', params=[f"SELECT nodeid FROM nodes WHERE nodeid != x'{NEW_VALUES_LIST['l3_id']}'"], description=['If you want to get specific nodeid values from the nodes table:'], response=sql_res3)
|
|
sql_res4 = l1.rpc.sql(f"SELECT nodeid FROM nodes WHERE nodeid IN (x'{l1.info['id']}', x'{l3.info['id']}')")
|
|
update_example(node=l1, method='sql', params=[f"SELECT nodeid FROM nodes WHERE nodeid IN (x'{NEW_VALUES_LIST['l1_id']}', x'{NEW_VALUES_LIST['l3_id']}')"], description=["If you want to compare a BLOB column, `x'hex'` or `X'hex'` are needed:"], response=sql_res4)
|
|
update_example(node=l1, method='sql', params=['SELECT peer_id, to_us_msat, total_msat, peerchannels_status.status FROM peerchannels INNER JOIN peerchannels_status ON peerchannels_status.row = peerchannels.rowid'], description=['Related tables are usually referenced by JOIN:'])
|
|
update_example(node=l2, method='sql', params=['SELECT COUNT(*) FROM forwards'], description=["Simple function usage, in this case COUNT. Strings inside arrays need \", and ' to protect them from the shell:"])
|
|
update_example(node=l1, method='sql', params=['SELECT * from peerchannels_features'])
|
|
example_log = getlog_res1['log']
|
|
for i, log_entry in enumerate(example_log):
|
|
if 'num_skipped' in log_entry:
|
|
log_entry['num_skipped'] = 144 + i
|
|
if 'time' in log_entry:
|
|
log_entry['time'] = f"{70.8 + i}00000000"
|
|
if 'node_id' in log_entry:
|
|
log_entry['node_id'] = 'nodeid' + ('01' * 30)
|
|
if log_entry.get('log', '').startswith('No peer channel with'):
|
|
log_entry['log'] = 'No peer channel with scid=228x1x1'
|
|
REPLACE_RESPONSE_VALUES.extend([
|
|
{'data_keys': ['any', 'psbt', 'initialpsbt'], 'original_value': psbtoutput_res1['psbt'], 'new_value': NEW_VALUES_LIST['init_psbt_1']},
|
|
{'data_keys': ['any', 'psbt', 'initialpsbt'], 'original_value': psbtoutput_res2['psbt'], 'new_value': NEW_VALUES_LIST['init_psbt_2']},
|
|
{'data_keys': ['any', 'psbt', 'initialpsbt'], 'original_value': psbtoutput_res3['psbt'], 'new_value': NEW_VALUES_LIST['init_psbt_3']},
|
|
{'data_keys': ['destination'], 'original_value': dest, 'new_value': NEW_VALUES_LIST['destination_1']},
|
|
{'data_keys': ['created_at'], 'original_value': decode_res2['created_at'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['signature'], 'original_value': decode_res2['signature'], 'new_value': NEW_VALUES_LIST['signature_1']},
|
|
{'data_keys': ['short_channel_id'], 'original_value': decode_res2['routes'][0][0]['short_channel_id'], 'new_value': NEW_VALUES_LIST['c23']},
|
|
{'data_keys': ['created_at'], 'original_value': decodepay_res1['created_at'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['signature'], 'original_value': decodepay_res1['signature'], 'new_value': NEW_VALUES_LIST['signature_2']},
|
|
{'data_keys': ['tx'], 'original_value': multiwithdraw_res1['tx'], 'new_value': NEW_VALUES_LIST['tx_55']},
|
|
{'data_keys': ['txid'], 'original_value': multiwithdraw_res1['txid'], 'new_value': NEW_VALUES_LIST['txid_55']},
|
|
{'data_keys': ['tx'], 'original_value': multiwithdraw_res2['tx'], 'new_value': NEW_VALUES_LIST['tx_56']},
|
|
{'data_keys': ['txid'], 'original_value': multiwithdraw_res2['txid'], 'new_value': NEW_VALUES_LIST['txid_56']},
|
|
{'data_keys': ['psbt'], 'original_value': signed_psbt, 'new_value': NEW_VALUES_LIST['psbt_1']},
|
|
{'data_keys': ['tx', 'hash'], 'original_value': sendpsbt_res1['tx'], 'new_value': NEW_VALUES_LIST['tx_61']},
|
|
{'data_keys': ['txid'], 'original_value': sendpsbt_res1['txid'], 'new_value': NEW_VALUES_LIST['txid_61']},
|
|
{'data_keys': ['destination'], 'original_value': address_l21['bech32'], 'new_value': NEW_VALUES_LIST['destination_2']},
|
|
{'data_keys': ['destination'], 'original_value': address_l22['p2tr'], 'new_value': NEW_VALUES_LIST['destination_3']},
|
|
{'data_keys': ['utxos'], 'original_value': utxos, 'new_value': example_utxos},
|
|
{'data_keys': ['tx'], 'original_value': withdraw_l21['tx'], 'new_value': NEW_VALUES_LIST['tx_91']},
|
|
{'data_keys': ['txid'], 'original_value': withdraw_l21['txid'], 'new_value': NEW_VALUES_LIST['withdraw_txid_l21']},
|
|
{'data_keys': ['psbt'], 'original_value': withdraw_l21['psbt'], 'new_value': NEW_VALUES_LIST['psbt_7']},
|
|
{'data_keys': ['tx'], 'original_value': withdraw_l22['tx'], 'new_value': NEW_VALUES_LIST['tx_92']},
|
|
{'data_keys': ['txid'], 'original_value': withdraw_l22['txid'], 'new_value': NEW_VALUES_LIST['withdraw_txid_l22']},
|
|
{'data_keys': ['psbt'], 'original_value': withdraw_l22['psbt'], 'new_value': NEW_VALUES_LIST['psbt_8']},
|
|
{'data_keys': ['created_at'], 'original_value': getlog_res1['created_at'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['bytes_used'], 'original_value': getlog_res1['bytes_used'], 'new_value': NEW_VALUES_LIST['bytes_used']},
|
|
{'data_keys': ['bytes_max'], 'original_value': getlog_res1['bytes_max'], 'new_value': NEW_VALUES_LIST['bytes_max']},
|
|
{'data_keys': ['log'], 'original_value': getlog_res1['log'], 'new_value': example_log},
|
|
])
|
|
logger.info('General Utils Done!')
|
|
return address_l22
|
|
except Exception as e:
|
|
logger.error(f'Error in generating utils examples: {e}')
|
|
raise
|
|
|
|
|
|
def generate_splice_examples(node_factory, bitcoind):
|
|
"""Generates splice related examples"""
|
|
try:
|
|
logger.info('Splice Start...')
|
|
global FUND_WALLET_AMOUNT_SAT, FUND_CHANNEL_AMOUNT_SAT
|
|
# Basic setup for l7->l8
|
|
options = [
|
|
{
|
|
'experimental-splicing': None,
|
|
'allow-deprecated-apis': True,
|
|
'allow_bad_gossip': True,
|
|
'broken_log': '.*',
|
|
'dev-bitcoind-poll': 3,
|
|
}.copy()
|
|
for i in range(2)
|
|
]
|
|
l7, l8 = node_factory.get_nodes(2, opts=options)
|
|
l7.fundwallet(FUND_WALLET_AMOUNT_SAT)
|
|
l7.rpc.connect(l8.info['id'], 'localhost', l8.port)
|
|
c78, c78res = l7.fundchannel(l8, FUND_CHANNEL_AMOUNT_SAT)
|
|
mine_funding_to_announce(bitcoind, [l7, l8])
|
|
l7.wait_channel_active(c78)
|
|
chan_id_78 = l7.get_channel_id(l8)
|
|
# Splice
|
|
funds_result_1 = l7.rpc.fundpsbt('109000sat', 'slow', 166, excess_as_change=True)
|
|
spinit_res1 = update_example(node=l7, method='splice_init', params={'channel_id': chan_id_78, 'relative_amount': 100000, 'initialpsbt': funds_result_1['psbt']})
|
|
spupdate1_res1 = l7.rpc.splice_update(chan_id_78, spinit_res1['psbt'])
|
|
assert(spupdate1_res1['commitments_secured'] is False)
|
|
spupdate2_res1 = update_example(node=l7, method='splice_update', params={'channel_id': chan_id_78, 'psbt': spupdate1_res1['psbt']})
|
|
assert(spupdate2_res1['commitments_secured'] is True)
|
|
signpsbt_res1 = l7.rpc.signpsbt(spupdate2_res1['psbt'])
|
|
spsigned_res1 = update_example(node=l7, method='splice_signed', params={'channel_id': chan_id_78, 'psbt': signpsbt_res1['signed_psbt']})
|
|
|
|
bitcoind.generate_block(1)
|
|
sync_blockheight(bitcoind, [l7])
|
|
l7.daemon.wait_for_log(' to CHANNELD_NORMAL')
|
|
time.sleep(1)
|
|
|
|
# Splice out
|
|
funds_result_2 = l7.rpc.addpsbtoutput(100000)
|
|
|
|
# Pay with fee by subtracting 5000 from channel balance
|
|
spinit_res2 = update_example(node=l7, method='splice_init', params=[chan_id_78, -105000, funds_result_2['psbt']])
|
|
spupdate1_res2 = l7.rpc.splice_update(chan_id_78, spinit_res2['psbt'])
|
|
assert(spupdate1_res2['commitments_secured'] is False)
|
|
spupdate2_res2 = update_example(node=l7, method='splice_update', params=[chan_id_78, spupdate1_res2['psbt']])
|
|
assert(spupdate2_res2['commitments_secured'] is True)
|
|
spsigned_res2 = update_example(node=l7, method='splice_signed', params={'channel_id': chan_id_78, 'psbt': spupdate2_res2['psbt']})
|
|
update_example(node=l7, method='stop', params={})
|
|
|
|
REPLACE_RESPONSE_VALUES.extend([
|
|
{'data_keys': ['any', 'channel_id', 'account'], 'original_value': chan_id_78, 'new_value': NEW_VALUES_LIST['c78_channel_id']},
|
|
{'data_keys': ['any', 'psbt'], 'original_value': spinit_res1['psbt'], 'new_value': NEW_VALUES_LIST['psbt_1']},
|
|
{'data_keys': ['any', 'psbt'], 'original_value': spinit_res2['psbt'], 'new_value': NEW_VALUES_LIST['psbt_2']},
|
|
{'data_keys': ['any', 'initialpsbt', 'psbt'], 'original_value': funds_result_1['psbt'], 'new_value': NEW_VALUES_LIST['psbt_3']},
|
|
{'data_keys': ['any', 'initialpsbt', 'psbt'], 'original_value': funds_result_2['psbt'], 'new_value': NEW_VALUES_LIST['psbt_4']},
|
|
{'data_keys': ['psbt'], 'original_value': spupdate2_res1['psbt'], 'new_value': NEW_VALUES_LIST['psbt_5_2']},
|
|
{'data_keys': ['tx'], 'original_value': spsigned_res1['tx'], 'new_value': NEW_VALUES_LIST['send_tx_1']},
|
|
{'data_keys': ['txid'], 'original_value': spsigned_res1['txid'], 'new_value': NEW_VALUES_LIST['send_txid_1']},
|
|
{'data_keys': ['psbt'], 'original_value': spsigned_res1['psbt'], 'new_value': NEW_VALUES_LIST['psbt_1']},
|
|
{'data_keys': ['tx'], 'original_value': spsigned_res2['tx'], 'new_value': NEW_VALUES_LIST['send_tx_2']},
|
|
{'data_keys': ['txid'], 'original_value': spsigned_res2['txid'], 'new_value': NEW_VALUES_LIST['send_txid_2']},
|
|
{'data_keys': ['psbt'], 'original_value': spsigned_res2['psbt'], 'new_value': NEW_VALUES_LIST['psbt_2']},
|
|
{'data_keys': ['psbt'], 'original_value': signpsbt_res1['signed_psbt'], 'new_value': NEW_VALUES_LIST['signed_psbt_1']},
|
|
{'data_keys': ['psbt'], 'original_value': spupdate1_res1['psbt'], 'new_value': NEW_VALUES_LIST['psbt_1']},
|
|
{'data_keys': ['any', 'psbt'], 'original_value': spupdate1_res2['psbt'], 'new_value': NEW_VALUES_LIST['psbt_2']},
|
|
])
|
|
logger.info('Splice Done!')
|
|
except Exception as e:
|
|
logger.error(f'Error in generating splicing examples: {e}')
|
|
raise
|
|
|
|
|
|
def generate_channels_examples(node_factory, bitcoind, l1, l3, l4, l5):
|
|
"""Generates fundchannel and openchannel related examples"""
|
|
try:
|
|
logger.info('Channels Start...')
|
|
global FUND_WALLET_AMOUNT_SAT, FUND_CHANNEL_AMOUNT_SAT
|
|
# Basic setup for l9->l10 for fundchannel examples
|
|
options = [
|
|
{
|
|
'may_reconnect': True,
|
|
'dev-no-reconnect': None,
|
|
'allow-deprecated-apis': True,
|
|
'allow_bad_gossip': True,
|
|
'broken_log': '.*',
|
|
'dev-bitcoind-poll': 3,
|
|
}.copy()
|
|
for i in range(2)
|
|
]
|
|
l9, l10 = node_factory.get_nodes(2, opts=options)
|
|
|
|
amount = 2 ** 24
|
|
l9.fundwallet(amount + 10000000)
|
|
bitcoind.generate_block(1)
|
|
wait_for(lambda: len(l9.rpc.listfunds()["outputs"]) != 0)
|
|
l9.rpc.connect(l10.info['id'], 'localhost', l10.port)
|
|
|
|
fund_start_res1 = update_example(node=l9, method='fundchannel_start', params=[l10.info['id'], amount])
|
|
outputs_1 = [{fund_start_res1['funding_address']: amount}]
|
|
example_outputs_1 = [{'bcrt1p00' + ('02' * 28): amount}]
|
|
tx_prep_1 = update_example(node=l9, method='txprepare', params=[outputs_1])
|
|
update_example(node=l9, method='fundchannel_cancel', params=[l10.info['id']])
|
|
txdiscard_res1 = update_example(node=l9, method='txdiscard', params=[tx_prep_1['txid']])
|
|
fund_start_res2 = update_example(node=l9, method='fundchannel_start', params={'id': l10.info['id'], 'amount': amount})
|
|
outputs_2 = [{fund_start_res2['funding_address']: amount}]
|
|
example_outputs_2 = [{'bcrt1p00' + ('03' * 28): amount}]
|
|
tx_prep_2 = update_example(node=l9, method='txprepare', params={'outputs': outputs_2})
|
|
fcc_res1 = update_example(node=l9, method='fundchannel_complete', params=[l10.info['id'], tx_prep_2['psbt']])
|
|
txsend_res1 = update_example(node=l9, method='txsend', params=[tx_prep_2['txid']])
|
|
l9.rpc.close(l10.info['id'])
|
|
|
|
bitcoind.generate_block(1)
|
|
sync_blockheight(bitcoind, [l9])
|
|
|
|
amount = 1000000
|
|
fund_start_res3 = l9.rpc.fundchannel_start(l10.info['id'], amount)
|
|
tx_prep_3 = l9.rpc.txprepare([{fund_start_res3['funding_address']: amount}])
|
|
update_example(node=l9, method='fundchannel_cancel', params={'id': l10.info['id']})
|
|
txdiscard_res2 = update_example(node=l9, method='txdiscard', params={'txid': tx_prep_3['txid']})
|
|
funding_addr = l9.rpc.fundchannel_start(l10.info['id'], amount)['funding_address']
|
|
tx_prep_4 = l9.rpc.txprepare([{funding_addr: amount}])
|
|
fcc_res2 = update_example(node=l9, method='fundchannel_complete', params={'id': l10.info['id'], 'psbt': tx_prep_4['psbt']})
|
|
txsend_res2 = update_example(node=l9, method='txsend', params={'txid': tx_prep_4['txid']})
|
|
l9.rpc.close(l10.info['id'])
|
|
|
|
# Basic setup for l11->l12 for openchannel examples
|
|
options = [
|
|
{
|
|
'experimental-dual-fund': None,
|
|
'may_reconnect': True,
|
|
'dev-no-reconnect': None,
|
|
'allow_warning': True,
|
|
'allow-deprecated-apis': True,
|
|
'allow_bad_gossip': True,
|
|
'broken_log': '.*',
|
|
'dev-bitcoind-poll': 3,
|
|
}.copy()
|
|
for i in range(2)
|
|
]
|
|
l11, l12 = node_factory.get_nodes(2, opts=options)
|
|
|
|
l11.fundwallet(FUND_WALLET_AMOUNT_SAT)
|
|
l11.rpc.connect(l12.info['id'], 'localhost', l12.port)
|
|
c1112res = l11.rpc.fundchannel(l12.info['id'], FUND_CHANNEL_AMOUNT_SAT)
|
|
chan_id = c1112res['channel_id']
|
|
vins = bitcoind.rpc.decoderawtransaction(c1112res['tx'])['vin']
|
|
assert(only_one(vins))
|
|
prev_utxos = ["{}:{}".format(vins[0]['txid'], vins[0]['vout'])]
|
|
example_utxos = ['utxo' + ('01' * 30) + ':1']
|
|
|
|
l11.daemon.wait_for_log(' to DUALOPEND_AWAITING_LOCKIN')
|
|
chan = only_one(l11.rpc.listpeerchannels(l12.info['id'])['channels'])
|
|
rate = int(chan['feerate']['perkw'])
|
|
next_feerate = '{}perkw'.format(rate * 4)
|
|
|
|
# Initiate an RBF
|
|
startweight = 42 + 172
|
|
initpsbt_1 = update_example(node=l11, method='utxopsbt', params=[FUND_CHANNEL_AMOUNT_SAT, next_feerate, startweight, prev_utxos, None, True, None, None, True])
|
|
openchannelbump_res1 = update_example(node=l11, method='openchannel_bump', params=[chan_id, FUND_CHANNEL_AMOUNT_SAT, initpsbt_1['psbt'], next_feerate])
|
|
|
|
update_example(node=l11, method='openchannel_abort', params={'channel_id': chan_id})
|
|
openchannelbump_res2 = update_example(node=l11, method='openchannel_bump', params={'channel_id': chan_id, 'amount': FUND_CHANNEL_AMOUNT_SAT, 'initialpsbt': initpsbt_1['psbt'], 'funding_feerate': next_feerate})
|
|
openchannelupdate_res1 = update_example(node=l11, method='openchannel_update', params={'channel_id': chan_id, 'psbt': openchannelbump_res2['psbt']})
|
|
signed_psbt_1 = update_example(node=l11, method='signpsbt', params={'psbt': openchannelupdate_res1['psbt']})
|
|
openchannelsigned_res1 = update_example(node=l11, method='openchannel_signed', params={'channel_id': chan_id, 'signed_psbt': signed_psbt_1['signed_psbt']})
|
|
|
|
# 5x the feerate to beat the min-relay fee
|
|
chan = only_one(l11.rpc.listpeerchannels(l12.info['id'])['channels'])
|
|
rate = int(chan['feerate']['perkw'])
|
|
next_feerate = '{}perkw'.format(rate * 5)
|
|
|
|
# Another RBF with double the channel amount
|
|
startweight = 42 + 172
|
|
initpsbt_2 = update_example(node=l11, method='utxopsbt', params={'satoshi': FUND_CHANNEL_AMOUNT_SAT * 2, 'feerate': next_feerate, 'startweight': startweight, 'utxos': prev_utxos, 'reservedok': True, 'excess_as_change': True})
|
|
openchannelbump_res3 = update_example(node=l11, method='openchannel_bump', params=[chan_id, FUND_CHANNEL_AMOUNT_SAT * 2, initpsbt_2['psbt'], next_feerate])
|
|
openchannelupdate_res2 = update_example(node=l11, method='openchannel_update', params=[chan_id, openchannelbump_res3['psbt']])
|
|
signed_psbt_2 = update_example(node=l11, method='signpsbt', params=[openchannelupdate_res2['psbt']])
|
|
openchannelsigned_res2 = update_example(node=l11, method='openchannel_signed', params=[chan_id, signed_psbt_2['signed_psbt']])
|
|
|
|
bitcoind.generate_block(1)
|
|
sync_blockheight(bitcoind, [l11])
|
|
l11.daemon.wait_for_log(' to CHANNELD_NORMAL')
|
|
|
|
# Fundpsbt, channelopen init, abort, unreserve
|
|
psbt_init_res1 = update_example(node=l11, method='fundpsbt', params={'satoshi': FUND_CHANNEL_AMOUNT_SAT, 'feerate': '253perkw', 'startweight': 250, 'reserve': 0})
|
|
openchannelinit_res1 = update_example(node=l11, method='openchannel_init', params={'id': l12.info['id'], 'amount': FUND_CHANNEL_AMOUNT_SAT, 'initialpsbt': psbt_init_res1['psbt']})
|
|
l11.rpc.openchannel_abort(openchannelinit_res1['channel_id'])
|
|
update_example(node=l11, method='unreserveinputs', params={'psbt': psbt_init_res1['psbt'], 'reserve': 200})
|
|
|
|
psbt_init_res2 = update_example(node=l11, method='fundpsbt', params={'satoshi': FUND_CHANNEL_AMOUNT_SAT // 2, 'feerate': 'urgent', 'startweight': 166, 'reserve': 0, 'excess_as_change': True, 'min_witness_weight': 110})
|
|
openchannelinit_res2 = update_example(node=l11, method='openchannel_init', params=[l12.info['id'], FUND_CHANNEL_AMOUNT_SAT // 2, psbt_init_res2['psbt']])
|
|
l11.rpc.openchannel_abort(openchannelinit_res2['channel_id'])
|
|
update_example(node=l11, method='unreserveinputs', params=[psbt_init_res2['psbt']])
|
|
|
|
# Reserveinputs
|
|
bitcoind.generate_block(1)
|
|
sync_blockheight(bitcoind, [l11])
|
|
outputs = l11.rpc.listfunds()['outputs']
|
|
psbt_1 = bitcoind.rpc.createpsbt([{'txid': outputs[0]['txid'], 'vout': outputs[0]['output']}], [])
|
|
update_example(node=l11, method='reserveinputs', params={'psbt': psbt_1})
|
|
l11.rpc.unreserveinputs(psbt_1)
|
|
psbt_2 = bitcoind.rpc.createpsbt([{'txid': outputs[1]['txid'], 'vout': outputs[1]['output']}], [])
|
|
update_example(node=l11, method='reserveinputs', params={'psbt': psbt_2})
|
|
l11.rpc.unreserveinputs(psbt_2)
|
|
|
|
# Multifundchannel 1
|
|
l3.rpc.connect(l5.info['id'], 'localhost', l5.port)
|
|
l4.rpc.connect(l1.info['id'], 'localhost', l1.port)
|
|
c35res = update_example(node=l3, method='fundchannel', params={'id': l5.info['id'], 'amount': FUND_CHANNEL_AMOUNT_SAT, 'announce': True})
|
|
outputs = l4.rpc.listfunds()['outputs']
|
|
utxo = f"{outputs[0]['txid']}:{outputs[0]['output']}"
|
|
c41res = update_example(node=l4, method='fundchannel',
|
|
params={'id': l1.info['id'], 'amount': 'all', 'feerate': 'normal', 'push_msat': 100000, 'utxos': [utxo]},
|
|
description=[f'This example shows how to to open new channel with peer 1 from one whole utxo (you can use **listfunds** command to get txid and vout):'])
|
|
# Close newly funded channels to bring the setup back to initial state
|
|
l3.rpc.close(c35res['channel_id'])
|
|
l4.rpc.close(c41res['channel_id'])
|
|
l3.rpc.disconnect(l5.info['id'], True)
|
|
l4.rpc.disconnect(l1.info['id'], True)
|
|
|
|
# Multifundchannel 2
|
|
l1.fundwallet(10**8)
|
|
l1.rpc.connect(l3.info['id'], 'localhost', l3.port)
|
|
l1.rpc.connect(l4.info['id'], 'localhost', l4.port)
|
|
l1.rpc.connect(l5.info['id'], 'localhost', l5.port)
|
|
destinations_1 = [
|
|
{
|
|
'id': f'{l3.info["id"]}@127.0.0.1:{l3.port}',
|
|
'amount': '20000sat'
|
|
},
|
|
{
|
|
'id': f'{l4.info["id"]}@127.0.0.1:{l4.port}',
|
|
'amount': '0.0003btc'
|
|
},
|
|
{
|
|
'id': f'{l5.info["id"]}@127.0.0.1:{l5.port}',
|
|
'amount': 'all'
|
|
}
|
|
]
|
|
example_destinations_1 = [
|
|
{
|
|
'id': 'nodeid' + ('03' * 30) + '@127.0.0.1:19736',
|
|
'amount': '20000sat'
|
|
},
|
|
{
|
|
'id': 'nodeid' + ('04' * 30) + '@127.0.0.1:19737',
|
|
'amount': '0.0003btc'
|
|
},
|
|
{
|
|
'id': 'nodeid' + ('05' * 30) + '@127.0.0.1:19738',
|
|
'amount': 'all'
|
|
}
|
|
]
|
|
multifund_res1 = update_example(node=l1, method='multifundchannel', params={
|
|
'destinations': destinations_1,
|
|
'feerate': '10000perkw',
|
|
'commitment_feerate': '2000perkw'
|
|
}, description=[
|
|
'This example opens three channels at once, with amounts 20,000 sats, 30,000 sats',
|
|
'and the final channel using all remaining funds (actually, capped at 16,777,215 sats',
|
|
'because large-channels is not enabled):'
|
|
])
|
|
for channel in multifund_res1['channel_ids']:
|
|
l1.rpc.close(channel['channel_id'])
|
|
l1.fundwallet(10**8)
|
|
|
|
destinations_2 = [
|
|
{
|
|
'id': f'03a389b3a2f7aa6f9f4ccc19f2bd7a2eba83596699e86b715caaaa147fc37f3144@127.0.0.1:{l3.port}',
|
|
'amount': 50000
|
|
},
|
|
{
|
|
'id': f'{l4.info["id"]}@127.0.0.1:{l4.port}',
|
|
'amount': 50000
|
|
},
|
|
{
|
|
'id': f'{l1.info["id"]}@127.0.0.1:{l1.port}',
|
|
'amount': 50000
|
|
}
|
|
]
|
|
example_destinations_2 = [
|
|
{
|
|
'id': f'fakenodeid' + ('03' * 28) + '@127.0.0.1:19736',
|
|
'amount': 50000
|
|
},
|
|
{
|
|
'id': 'nodeid' + ('04' * 30) + '@127.0.0.1:19737',
|
|
'amount': 50000
|
|
},
|
|
{
|
|
'id': 'nodeid' + ('01' * 30) + '@127.0.0.1:19734',
|
|
'amount': 50000
|
|
}
|
|
]
|
|
multifund_res2 = update_example(node=l1, method='multifundchannel', params={'destinations': destinations_2, 'minchannels': 1})
|
|
# Close newly funded channels to bring the setup back to initial state
|
|
for channel in multifund_res2['channel_ids']:
|
|
l1.rpc.close(channel['channel_id'])
|
|
REPLACE_RESPONSE_VALUES.extend([
|
|
{'data_keys': ['any', 'id', 'pubkey', 'destination'], 'original_value': l10.info['id'], 'new_value': NEW_VALUES_LIST['l10_id']},
|
|
{'data_keys': ['any', 'id', 'pubkey', 'destination'], 'original_value': l12.info['id'], 'new_value': NEW_VALUES_LIST['l12_id']},
|
|
{'data_keys': ['any', 'txid'], 'original_value': tx_prep_1['txid'], 'new_value': NEW_VALUES_LIST['txprep_txid_1']},
|
|
{'data_keys': ['initialpsbt', 'psbt', 'signed_psbt'], 'original_value': tx_prep_1['psbt'], 'new_value': NEW_VALUES_LIST['psbt_9']},
|
|
{'data_keys': ['unsigned_tx'], 'original_value': tx_prep_2['unsigned_tx'], 'new_value': NEW_VALUES_LIST['unsigned_tx_1']},
|
|
{'data_keys': ['any', 'initialpsbt', 'psbt', 'signed_psbt'], 'original_value': tx_prep_2['psbt'], 'new_value': NEW_VALUES_LIST['psbt_10']},
|
|
{'data_keys': ['any', 'txid'], 'original_value': tx_prep_2['txid'], 'new_value': NEW_VALUES_LIST['txprep_txid_2']},
|
|
{'data_keys': ['any', 'txid'], 'original_value': tx_prep_3['txid'], 'new_value': NEW_VALUES_LIST['txprep_txid_3']},
|
|
{'data_keys': ['txid'], 'original_value': tx_prep_4['txid'], 'new_value': NEW_VALUES_LIST['txprep_txid_4']},
|
|
{'data_keys': ['initialpsbt', 'psbt', 'signed_psbt'], 'original_value': tx_prep_4['psbt'], 'new_value': NEW_VALUES_LIST['psbt_12']},
|
|
{'data_keys': ['channel_id', 'account'], 'original_value': fcc_res1['channel_id'], 'new_value': NEW_VALUES_LIST['c910_channel_id_1']},
|
|
{'data_keys': ['channel_id', 'account'], 'original_value': fcc_res2['channel_id'], 'new_value': NEW_VALUES_LIST['c910_channel_id_2']},
|
|
{'data_keys': ['txid'], 'original_value': c1112res['txid'], 'new_value': NEW_VALUES_LIST['c1112_txid']},
|
|
{'data_keys': ['channel_id', 'account'], 'original_value': c1112res['channel_id'], 'new_value': NEW_VALUES_LIST['c1112_channel_id']},
|
|
{'data_keys': ['tx'], 'original_value': c35res['tx'], 'new_value': NEW_VALUES_LIST['c35_tx']},
|
|
{'data_keys': ['txid'], 'original_value': c35res['txid'], 'new_value': NEW_VALUES_LIST['c35_txid']},
|
|
{'data_keys': ['channel_id', 'account'], 'original_value': c35res['channel_id'], 'new_value': NEW_VALUES_LIST['c35_channel_id']},
|
|
{'data_keys': ['tx'], 'original_value': c41res['tx'], 'new_value': NEW_VALUES_LIST['c41_tx']},
|
|
{'data_keys': ['txid', 'funding_txid'], 'original_value': c41res['txid'], 'new_value': NEW_VALUES_LIST['c41_txid']},
|
|
{'data_keys': ['channel_id', 'account'], 'original_value': c41res['channel_id'], 'new_value': NEW_VALUES_LIST['c41_channel_id']},
|
|
{'data_keys': ['destinations'], 'original_value': destinations_1, 'new_value': example_destinations_1},
|
|
{'data_keys': ['channel_id', 'account'], 'original_value': multifund_res1['channel_ids'][0]['channel_id'], 'new_value': NEW_VALUES_LIST['mf_channel_id_1']},
|
|
{'data_keys': ['channel_id', 'account'], 'original_value': multifund_res1['channel_ids'][1]['channel_id'], 'new_value': NEW_VALUES_LIST['mf_channel_id_2']},
|
|
{'data_keys': ['channel_id', 'account'], 'original_value': multifund_res1['channel_ids'][2]['channel_id'], 'new_value': NEW_VALUES_LIST['mf_channel_id_3']},
|
|
{'data_keys': ['tx'], 'original_value': multifund_res1['tx'], 'new_value': NEW_VALUES_LIST['multi_tx_1']},
|
|
{'data_keys': ['txid', 'funding_txid'], 'original_value': multifund_res1['txid'], 'new_value': NEW_VALUES_LIST['multi_txid_1']},
|
|
{'data_keys': ['destinations'], 'original_value': destinations_2, 'new_value': example_destinations_2},
|
|
{'data_keys': ['channel_id', 'account'], 'original_value': multifund_res2['channel_ids'][0]['channel_id'], 'new_value': NEW_VALUES_LIST['mf_channel_id_4']},
|
|
{'data_keys': ['tx'], 'original_value': multifund_res2['tx'], 'new_value': NEW_VALUES_LIST['multi_tx_2']},
|
|
{'data_keys': ['txid'], 'original_value': multifund_res2['txid'], 'new_value': NEW_VALUES_LIST['multi_txid_2']},
|
|
{'data_keys': ['message'], 'original_value': multifund_res2['failed'][0]['error']['message'], 'new_value': NEW_VALUES_LIST['error_message_1']},
|
|
{'data_keys': ['utxos'], 'original_value': [utxo], 'new_value': [NEW_VALUES_LIST['c35_txid'] + ':1']},
|
|
{'data_keys': ['any', 'funding_address'], 'original_value': fund_start_res1['funding_address'], 'new_value': NEW_VALUES_LIST['destination_4']},
|
|
{'data_keys': ['any', 'outputs'], 'original_value': outputs_1, 'new_value': example_outputs_1},
|
|
{'data_keys': ['scriptpubkey'], 'original_value': fund_start_res1['scriptpubkey'], 'new_value': NEW_VALUES_LIST['script_pubkey_1']},
|
|
{'data_keys': ['any', 'funding_address'], 'original_value': fund_start_res2['funding_address'], 'new_value': NEW_VALUES_LIST['destination_5']},
|
|
{'data_keys': ['any', 'outputs'], 'original_value': outputs_2, 'new_value': example_outputs_2},
|
|
{'data_keys': ['scriptpubkey'], 'original_value': fund_start_res2['scriptpubkey'], 'new_value': NEW_VALUES_LIST['script_pubkey_2']},
|
|
{'data_keys': ['initialpsbt', 'psbt'], 'original_value': psbt_init_res1['psbt'], 'new_value': NEW_VALUES_LIST['psbt_13']},
|
|
{'data_keys': ['any', 'initialpsbt', 'psbt'], 'original_value': psbt_init_res2['psbt'], 'new_value': NEW_VALUES_LIST['psbt_14']},
|
|
{'data_keys': ['any', 'txid'], 'original_value': initpsbt_1['reservations'][0]['txid'], 'new_value': NEW_VALUES_LIST['utxo_1']},
|
|
{'data_keys': ['any', 'initialpsbt', 'psbt'], 'original_value': initpsbt_1['psbt'], 'new_value': NEW_VALUES_LIST['psbt_15']},
|
|
{'data_keys': ['any', 'initialpsbt', 'psbt'], 'original_value': initpsbt_2['psbt'], 'new_value': NEW_VALUES_LIST['psbt_16']},
|
|
{'data_keys': ['any', 'txid'], 'original_value': initpsbt_2['reservations'][0]['txid'], 'new_value': NEW_VALUES_LIST['utxo_1']},
|
|
{'data_keys': ['initialpsbt', 'psbt', 'signed_psbt'], 'original_value': openchannelinit_res1['psbt'], 'new_value': NEW_VALUES_LIST['psbt_17']},
|
|
{'data_keys': ['funding_serial'], 'original_value': openchannelinit_res1['funding_serial'], 'new_value': NEW_VALUES_LIST['funding_serial_1']},
|
|
{'data_keys': ['initialpsbt', 'psbt', 'signed_psbt'], 'original_value': openchannelinit_res2['psbt'], 'new_value': NEW_VALUES_LIST['psbt_18']},
|
|
{'data_keys': ['funding_serial'], 'original_value': openchannelinit_res2['funding_serial'], 'new_value': NEW_VALUES_LIST['funding_serial_2']},
|
|
{'data_keys': ['initialpsbt', 'psbt', 'signed_psbt'], 'original_value': openchannelbump_res1['psbt'], 'new_value': NEW_VALUES_LIST['psbt_19']},
|
|
{'data_keys': ['initialpsbt', 'psbt', 'signed_psbt'], 'original_value': openchannelbump_res2['psbt'], 'new_value': NEW_VALUES_LIST['psbt_20']},
|
|
{'data_keys': ['any', 'initialpsbt', 'psbt', 'signed_psbt'], 'original_value': openchannelbump_res3['psbt'], 'new_value': NEW_VALUES_LIST['psbt_21']},
|
|
{'data_keys': ['funding_serial'], 'original_value': openchannelbump_res1['funding_serial'], 'new_value': NEW_VALUES_LIST['funding_serial_3']},
|
|
{'data_keys': ['funding_serial'], 'original_value': openchannelbump_res2['funding_serial'], 'new_value': NEW_VALUES_LIST['funding_serial_4']},
|
|
{'data_keys': ['funding_serial'], 'original_value': openchannelbump_res3['funding_serial'], 'new_value': NEW_VALUES_LIST['funding_serial_5']},
|
|
{'data_keys': ['signed_psbt'], 'original_value': signed_psbt_1['signed_psbt'], 'new_value': NEW_VALUES_LIST['psbt_22']},
|
|
{'data_keys': ['tx'], 'original_value': openchannelsigned_res1['tx'], 'new_value': NEW_VALUES_LIST['ocs_tx_1']},
|
|
{'data_keys': ['txid'], 'original_value': openchannelsigned_res1['txid'], 'new_value': NEW_VALUES_LIST['ocs_txid_1']},
|
|
{'data_keys': ['any', 'signed_psbt'], 'original_value': signed_psbt_2['signed_psbt'], 'new_value': NEW_VALUES_LIST['psbt_23']},
|
|
{'data_keys': ['tx'], 'original_value': openchannelsigned_res2['tx'], 'new_value': NEW_VALUES_LIST['ocs_tx_2']},
|
|
{'data_keys': ['txid'], 'original_value': openchannelsigned_res2['txid'], 'new_value': NEW_VALUES_LIST['ocs_txid_2']},
|
|
{'data_keys': ['psbt'], 'original_value': psbt_1, 'new_value': NEW_VALUES_LIST['psbt_24']},
|
|
{'data_keys': ['psbt'], 'original_value': psbt_2, 'new_value': NEW_VALUES_LIST['psbt_25']},
|
|
{'data_keys': ['any'], 'original_value': prev_utxos, 'new_value': example_utxos},
|
|
{'data_keys': ['unsigned_tx'], 'original_value': txdiscard_res1['unsigned_tx'], 'new_value': NEW_VALUES_LIST['unsigned_tx_3']},
|
|
{'data_keys': ['unsigned_tx'], 'original_value': txdiscard_res2['unsigned_tx'], 'new_value': NEW_VALUES_LIST['unsigned_tx_4']},
|
|
{'data_keys': ['tx'], 'original_value': txsend_res1['tx'], 'new_value': NEW_VALUES_LIST['txsend_tx_1']},
|
|
{'data_keys': ['psbt'], 'original_value': txsend_res1['psbt'], 'new_value': NEW_VALUES_LIST['psbt_24']},
|
|
{'data_keys': ['tx'], 'original_value': txsend_res2['tx'], 'new_value': NEW_VALUES_LIST['txsend_tx_2']},
|
|
{'data_keys': ['psbt'], 'original_value': txsend_res2['psbt'], 'new_value': NEW_VALUES_LIST['psbt_26']},
|
|
])
|
|
l1.rpc.disconnect(l3.info['id'], True)
|
|
l1.rpc.disconnect(l4.info['id'], True)
|
|
l1.rpc.disconnect(l5.info['id'], True)
|
|
bitcoind.generate_block(1)
|
|
sync_blockheight(bitcoind, [l1, l3, l4, l5])
|
|
logger.info('Channels Done!')
|
|
except Exception as e:
|
|
logger.error(f'Error in generating fundchannel and openchannel examples: {e}')
|
|
raise
|
|
|
|
|
|
def generate_autoclean_delete_examples(l1, l2, l3, l4, l5, c12, c23):
|
|
"""Records autoclean and delete examples"""
|
|
try:
|
|
logger.info('Auto-clean and Delete Start...')
|
|
global FUND_CHANNEL_AMOUNT_SAT
|
|
l2.rpc.close(l5.info['id'])
|
|
dfc_res1 = update_example(node=l2, method='dev-forget-channel', params={'id': l5.info['id']}, description=[f'Forget a channel by peer pubkey when only one channel exists with the peer:'])
|
|
|
|
# Create invoices for delpay and delinvoice examples
|
|
inv_l35 = l3.rpc.invoice('50000sat', 'lbl_l35', 'l35 description')
|
|
inv_l36 = l3.rpc.invoice('50000sat', 'lbl_l36', 'l36 description')
|
|
inv_l37 = l3.rpc.invoice('50000sat', 'lbl_l37', 'l37 description')
|
|
|
|
# For MPP payment from l1 to l4; will use for delpay groupdid and partid example
|
|
inv_l41 = l4.rpc.invoice('5000sat', 'lbl_l41', 'l41 description')
|
|
l2.rpc.connect(l4.info['id'], 'localhost', l4.port)
|
|
c24, c24res = l2.fundchannel(l4, FUND_CHANNEL_AMOUNT_SAT)
|
|
l2.rpc.pay(l4.rpc.invoice(500000000, 'lbl balance l2 to l4', 'description send some sats l2 to l4')['bolt11'])
|
|
# Create two routes; l1->l2->l3->l4 and l1->l2->l4
|
|
route_l1_l4 = l1.rpc.getroute(l4.info['id'], '4000sat', 1)['route']
|
|
route_l1_l2_l4 = [{'amount_msat': '1000sat', 'id': l2.info['id'], 'delay': 5, 'channel': c12},
|
|
{'amount_msat': '1000sat', 'id': l4.info['id'], 'delay': 5, 'channel': c24}]
|
|
l1.rpc.sendpay(route_l1_l4, inv_l41['payment_hash'], amount_msat='5000sat', groupid=1, partid=1, payment_secret=inv_l41['payment_secret'])
|
|
l1.rpc.sendpay(route_l1_l2_l4, inv_l41['payment_hash'], amount_msat='5000sat', groupid=1, partid=2, payment_secret=inv_l41['payment_secret'])
|
|
# Close l2->l4 for initial state
|
|
l2.rpc.close(l4.info['id'])
|
|
l2.rpc.disconnect(l4.info['id'], True)
|
|
|
|
# Delinvoice
|
|
l1.rpc.pay(inv_l35['bolt11'])
|
|
l1.rpc.pay(inv_l37['bolt11'])
|
|
delinv_res1 = update_example(node=l3, method='delinvoice', params={'label': 'lbl_l36', 'status': 'unpaid'})
|
|
|
|
# invoice already deleted, pay will fail; used for delpay failed example
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.pay(inv_l36['bolt11'])
|
|
|
|
listsendpays_l1 = l1.rpc.listsendpays()['payments']
|
|
sendpay_g1_p1 = next((x for x in listsendpays_l1 if 'groupid' in x and x['groupid'] == 1 and 'partid' in x and x['partid'] == 2), None)
|
|
delpay_res1 = update_example(node=l1, method='delpay', params={'payment_hash': listsendpays_l1[0]['payment_hash'], 'status': 'complete'})
|
|
delpay_res2 = update_example(node=l1, method='delpay', params=[listsendpays_l1[-1]['payment_hash'], listsendpays_l1[-1]['status']])
|
|
delpay_res3 = update_example(node=l1, method='delpay', params={'payment_hash': sendpay_g1_p1['payment_hash'], 'status': sendpay_g1_p1['status'], 'groupid': 1, 'partid': 2})
|
|
delinv_res2 = update_example(node=l3, method='delinvoice', params={'label': 'lbl_l37', 'status': 'paid', 'desconly': True})
|
|
|
|
# Delforward
|
|
failed_forwards = l2.rpc.listforwards('failed')['forwards']
|
|
local_failed_forwards = l2.rpc.listforwards('local_failed')['forwards']
|
|
if len(local_failed_forwards) > 0 and 'in_htlc_id' in local_failed_forwards[0]:
|
|
update_example(node=l2, method='delforward', params={'in_channel': c12, 'in_htlc_id': local_failed_forwards[0]['in_htlc_id'], 'status': 'local_failed'})
|
|
if len(failed_forwards) > 0 and 'in_htlc_id' in failed_forwards[0]:
|
|
update_example(node=l2, method='delforward', params={'in_channel': c12, 'in_htlc_id': failed_forwards[0]['in_htlc_id'], 'status': 'failed'})
|
|
dfc_res2 = update_example(node=l2, method='dev-forget-channel', params={'id': l3.info['id'], 'short_channel_id': c23, 'force': True}, description=[f'Forget a channel by short channel id when peer has multiple channels:'])
|
|
|
|
# Autoclean
|
|
update_example(node=l2, method='autoclean-once', params=['failedpays', 1])
|
|
update_example(node=l2, method='autoclean-once', params=['succeededpays', 1])
|
|
update_example(node=l2, method='autoclean-status', params={'subsystem': 'expiredinvoices'})
|
|
update_example(node=l2, method='autoclean-status', params={})
|
|
REPLACE_RESPONSE_VALUES.extend([
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': delinv_res1['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_di_1']},
|
|
{'data_keys': ['payment_hash'], 'original_value': delinv_res1['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_di_1']},
|
|
{'data_keys': ['expires_at'], 'original_value': delinv_res1['expires_at'], 'new_value': NEW_VALUES_LIST['time_at_900']},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': delinv_res2['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_di_2']},
|
|
{'data_keys': ['payment_hash'], 'original_value': delinv_res2['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_di_2']},
|
|
{'data_keys': ['paid_at'], 'original_value': delinv_res2['paid_at'], 'new_value': NEW_VALUES_LIST['time_at_850']},
|
|
{'data_keys': ['expires_at'], 'original_value': delinv_res2['expires_at'], 'new_value': NEW_VALUES_LIST['time_at_900']},
|
|
{'data_keys': ['payment_preimage'], 'original_value': delinv_res2['payment_preimage'], 'new_value': NEW_VALUES_LIST['payment_preimage_di_1']},
|
|
{'data_keys': ['payment_hash'], 'original_value': delpay_res1['payments'][0]['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_dp_1']},
|
|
{'data_keys': ['payment_preimage'], 'original_value': delpay_res1['payments'][0]['payment_preimage'], 'new_value': NEW_VALUES_LIST['payment_preimage_dp_1']},
|
|
{'data_keys': ['any', 'bolt11'], 'original_value': delpay_res1['payments'][0]['bolt11'], 'new_value': NEW_VALUES_LIST['bolt11_dp_1']},
|
|
{'data_keys': ['created_at'], 'original_value': delpay_res1['payments'][0]['created_at'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['completed_at'], 'original_value': delpay_res1['payments'][0]['completed_at'], 'new_value': NEW_VALUES_LIST['time_at_850']},
|
|
{'data_keys': ['any', 'payment_hash'], 'original_value': delpay_res2['payments'][0]['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_dp_2']},
|
|
{'data_keys': ['created_at'], 'original_value': delpay_res2['payments'][0]['created_at'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['completed_at'], 'original_value': delpay_res2['payments'][0]['completed_at'], 'new_value': NEW_VALUES_LIST['time_at_850']},
|
|
{'data_keys': ['payment_hash'], 'original_value': delpay_res3['payments'][0]['payment_hash'], 'new_value': NEW_VALUES_LIST['payment_hash_dp_3']},
|
|
{'data_keys': ['created_at'], 'original_value': delpay_res3['payments'][0]['created_at'], 'new_value': NEW_VALUES_LIST['time_at_800']},
|
|
{'data_keys': ['completed_at'], 'original_value': delpay_res3['payments'][0]['completed_at'], 'new_value': NEW_VALUES_LIST['time_at_850']},
|
|
{'data_keys': ['funding_txid'], 'original_value': dfc_res1['funding_txid'], 'new_value': NEW_VALUES_LIST['funding_txid_1']},
|
|
{'data_keys': ['funding_txid'], 'original_value': dfc_res2['funding_txid'], 'new_value': NEW_VALUES_LIST['funding_txid_2']},
|
|
])
|
|
logger.info('Auto-clean and Delete Done!')
|
|
except Exception as e:
|
|
logger.error(f'Error in generating autoclean and delete examples: {e}')
|
|
raise
|
|
|
|
|
|
def generate_backup_recovery_examples(node_factory, l4, l5, l6):
|
|
"""Node backup and recovery examples"""
|
|
try:
|
|
logger.info('Backup and Recovery Start...')
|
|
|
|
# New node l13 used for recover and exposesecret examples
|
|
l13 = node_factory.get_node(options={'exposesecret-passphrase': "test_exposesecret"})
|
|
update_example(node=l13, method='exposesecret', params={'passphrase': 'test_exposesecret'})
|
|
update_example(node=l13, method='exposesecret', params=['test_exposesecret', 'cln2'])
|
|
|
|
update_example(node=l5, method='makesecret', params=['73636220736563726574'])
|
|
update_example(node=l5, method='makesecret', params={'string': 'scb secret'})
|
|
emergencyrecover_res1 = l4.rpc.emergencyrecover()
|
|
emergencyrecover_res1['stubs'].sort()
|
|
update_example(node=l4, method='emergencyrecover', params={}, response=emergencyrecover_res1)
|
|
update_example(node=l4, method='getemergencyrecoverdata', params={}, response='emergencyrecoverdata' + ('01' * 827))
|
|
backup_l4 = update_example(node=l4, method='staticbackup', params={})
|
|
|
|
# Recover channels
|
|
l4.stop()
|
|
os.unlink(os.path.join(l4.daemon.lightning_dir, TEST_NETWORK, 'lightningd.sqlite3'))
|
|
l4.start()
|
|
time.sleep(1)
|
|
recoverchannel_res1 = l4.rpc.recoverchannel(backup_l4['scb'])
|
|
recoverchannel_res1['stubs'].sort()
|
|
update_example(node=l4, method='recoverchannel', params={'scb': backup_l4['scb']}, response=recoverchannel_res1)
|
|
example_scb = [
|
|
'0000000000000001' + NEW_VALUES_LIST['c34_channel_id'] + NEW_VALUES_LIST['l3_id'] + '00017f000001' + ('0340' * 23) + '0003401000',
|
|
'0000000000000002' + NEW_VALUES_LIST['c34_2_channel_id'] + NEW_VALUES_LIST['l3_id'] + '00017f000001' + ('0342' * 23) + '0003401000',
|
|
'0000000000000003' + NEW_VALUES_LIST['c41_channel_id'] + NEW_VALUES_LIST['l1_id'] + '00017f000001' + ('0410' * 23) + '0003401000',
|
|
'0000000000000004' + NEW_VALUES_LIST['c12_channel_id'] + NEW_VALUES_LIST['l1_id'] + '00017f000001' + ('0120' * 23) + '0003401000',
|
|
'0000000000000005' + NEW_VALUES_LIST['mf_channel_id_4'] + NEW_VALUES_LIST['l1_id'] + '00017f000001' + ('0152' * 23) + '0003401000',
|
|
'0000000000000006' + NEW_VALUES_LIST['mf_channel_id_5'] + NEW_VALUES_LIST['l2_id'] + '00017f000001' + ('0124' * 23) + '0003401000',
|
|
]
|
|
# Emergency recover
|
|
l5.stop()
|
|
os.unlink(os.path.join(l5.daemon.lightning_dir, TEST_NETWORK, 'lightningd.sqlite3'))
|
|
l5.start()
|
|
time.sleep(1)
|
|
emergencyrecover_res2 = l5.rpc.emergencyrecover()
|
|
emergencyrecover_res2['stubs'].sort()
|
|
update_example(node=l5, method='emergencyrecover', params={}, response=emergencyrecover_res2)
|
|
|
|
# Recover
|
|
def get_hsm_secret(n):
|
|
"""Returns codex32 and hex"""
|
|
try:
|
|
hsmfile = os.path.join(n.daemon.lightning_dir, TEST_NETWORK, "hsm_secret")
|
|
codex32 = subprocess.check_output(["tools/hsmtool", "getcodexsecret", hsmfile, "leet"]).decode('utf-8').strip()
|
|
with open(hsmfile, "rb") as f:
|
|
hexhsm = f.read().hex()
|
|
return codex32, hexhsm
|
|
except Exception as e:
|
|
logger.error(f'Error in getting hsm secret: {e}')
|
|
raise
|
|
|
|
_, l6hex = get_hsm_secret(l6)
|
|
l13codex32, _ = get_hsm_secret(l13)
|
|
update_example(node=l6, method='recover', params={'hsmsecret': l6hex})
|
|
update_example(node=l13, method='recover', params={'hsmsecret': l13codex32})
|
|
REPLACE_RESPONSE_VALUES.extend([
|
|
{'data_keys': ['hsmsecret'], 'original_value': l13codex32, 'new_value': NEW_VALUES_LIST['hsm_secret_cdx_1']},
|
|
{'data_keys': ['scb'], 'original_value': backup_l4['scb'], 'new_value': example_scb},
|
|
{'data_keys': ['channel_id', 'account'], 'original_value': backup_l4['scb'][5][16:(16 + 64)], 'new_value': NEW_VALUES_LIST['mf_channel_id_5']},
|
|
])
|
|
logger.info('Backup and Recovery Done!')
|
|
except Exception as e:
|
|
logger.error(f'Error in generating backup and recovery examples: {e}')
|
|
raise
|
|
|
|
|
|
def generate_list_examples(l1, l2, l3, c12, c23_2, inv_l31, inv_l32, offer_l23, inv_req_l1_l22, address_l22):
|
|
"""Generates lists rpc examples"""
|
|
try:
|
|
logger.info('Lists Start...')
|
|
# Transactions Lists
|
|
FUNDS_LEN = 3
|
|
listfunds_res1 = l1.rpc.listfunds()
|
|
listfunds_res1 = update_list_responses(listfunds_res1, list_key='outputs', slice_upto=FUNDS_LEN)
|
|
listfunds_res1['channels'] = [channel for channel in listfunds_res1['channels'] if channel['peer_id'] != '0382ce59ebf18be7d84677c2e35f23294b9992ceca95491fcf8a56c6cb2d9de199']
|
|
listfunds_res1['channels'] = sorted(listfunds_res1['channels'], key=lambda x: x['peer_id'])
|
|
for i in range(1, FUNDS_LEN + 1):
|
|
lfoutput = listfunds_res1['outputs'][i - 1]
|
|
lfchannel = listfunds_res1['channels'][i - 1]
|
|
lfoutput['output'] = i + 1
|
|
lfoutput['txid'] = 'txid' + (('0000' + str(i)) * 12)
|
|
lfoutput['scriptpubkey'] = 'scriptpubkey' + (f"{i:02}" * 28)
|
|
lfoutput['address'] = 'bcrt1p00' + ('04' * 28)
|
|
lfoutput['blockheight'] = NEW_VALUES_LIST['blockheight_160']
|
|
lfoutput['amount_msat'] = 25000000 + (i * 1000000)
|
|
lfchannel['funding_output'] = i
|
|
lfchannel['funding_txid'] = 'txid' + (('0100' + str(i)) * 12)
|
|
lfchannel['amount_msat'] = 10000000 + (i * 1000000)
|
|
lfchannel['our_amount_msat'] = 35000000 + (i * 1000000)
|
|
update_example(node=l1, method='listfunds', params={}, response=listfunds_res1)
|
|
|
|
listforwards_res1 = l2.rpc.listforwards(in_channel=c12, out_channel=c23_2, status='settled')
|
|
listforwards_res1 = update_list_responses(listforwards_res1, list_key='forwards', slice_upto=5, update_func=lambda x, i: x.update({'received_time': NEW_VALUES_LIST['time_at_800'] + (i * 10000), 'resolved_time': NEW_VALUES_LIST['time_at_850'] + (i * 10000)}))
|
|
update_example(node=l2, method='listforwards', params={'in_channel': c12, 'out_channel': c23_2, 'status': 'settled'}, response=listforwards_res1)
|
|
listforwards_res2 = l2.rpc.listforwards()
|
|
listforwards_res2 = update_list_responses(listforwards_res2, list_key='forwards', slice_upto=5, update_func=lambda x, i: x.update({'received_time': NEW_VALUES_LIST['time_at_800'] + (i * 10000), 'resolved_time': NEW_VALUES_LIST['time_at_850'] + (i * 10000)}))
|
|
update_example(node=l2, method='listforwards', params={}, response=listforwards_res2)
|
|
|
|
listinvoices_res1 = l2.rpc.listinvoices(label='lbl_l21')
|
|
listinvoices_res1 = update_list_responses(listinvoices_res1, list_key='invoices', slice_upto=5, update_func=lambda x, i: x.update({'paid_at': NEW_VALUES_LIST['time_at_850'] + (i * 10000), 'expires_at': NEW_VALUES_LIST['time_at_900'] + (i * 10000)}))
|
|
update_example(node=l2, method='listinvoices', params={'label': 'lbl_l21'}, response=listinvoices_res1)
|
|
listinvoices_res2 = l2.rpc.listinvoices()
|
|
listinvoices_res2 = update_list_responses(listinvoices_res2, list_key='invoices', slice_upto=5, update_func=lambda x, i: x.update({'paid_at': NEW_VALUES_LIST['time_at_850'] + (i * 10000), 'expires_at': NEW_VALUES_LIST['time_at_900'] + (i * 10000)}))
|
|
update_example(node=l2, method='listinvoices', params={}, response=listinvoices_res2)
|
|
|
|
listhtlcs_res1 = l1.rpc.listhtlcs(c12)
|
|
listhtlcs_res1 = update_list_responses(listhtlcs_res1, list_key='htlcs')
|
|
update_example(node=l1, method='listhtlcs', params=[c12], response=listhtlcs_res1)
|
|
listhtlcs_res2 = l1.rpc.listhtlcs()
|
|
listhtlcs_res2 = update_list_responses(listhtlcs_res2, list_key='htlcs')
|
|
update_example(node=l1, method='listhtlcs', params={}, response=listhtlcs_res2)
|
|
|
|
listsendpays_res1 = l1.rpc.listsendpays(bolt11=inv_l31['bolt11'])
|
|
listsendpays_res1 = update_list_responses(listsendpays_res1, list_key='payments', slice_upto=5, update_func=lambda x, i: x.update({'created_at': NEW_VALUES_LIST['time_at_800'] + (i * 10000), 'completed_at': NEW_VALUES_LIST['time_at_900'] + (i * 10000)}))
|
|
update_example(node=l1, method='listsendpays', params={'bolt11': inv_l31['bolt11']}, response=listsendpays_res1)
|
|
listsendpays_res2 = l1.rpc.listsendpays()
|
|
listsendpays_res2 = update_list_responses(listsendpays_res2, list_key='payments', slice_upto=5, update_func=lambda x, i: x.update({'created_at': NEW_VALUES_LIST['time_at_800'] + (i * 10000), 'completed_at': NEW_VALUES_LIST['time_at_900'] + (i * 10000)}))
|
|
update_example(node=l1, method='listsendpays', params={}, response=listsendpays_res2)
|
|
|
|
listpays_res1 = l2.rpc.listpays(bolt11=inv_l32['bolt11'])
|
|
listpays_res1 = update_list_responses(listpays_res1, list_key='pays')
|
|
update_example(node=l2, method='listpays', params={'bolt11': inv_l32['bolt11']}, response=listpays_res1)
|
|
listpays_res2 = l2.rpc.listpays()
|
|
listpays_res2 = update_list_responses(listpays_res2, list_key='pays')
|
|
update_example(node=l2, method='listpays', params={}, response=listpays_res2)
|
|
|
|
listtransactions_res1 = l1.rpc.listtransactions()
|
|
listtransactions_res1 = update_list_responses(listtransactions_res1, list_key='transactions', slice_upto=2)
|
|
for i, transaction in enumerate(listtransactions_res1['transactions'], start=1):
|
|
transaction['hash'] = 'txid' + (('7000' + str(i)) * 11)
|
|
transaction['rawtx'] = '02000000000101lstx' + (('7000' + str(i)) * 34)
|
|
transaction['locktime'] = 549000000 + (i * 100)
|
|
transaction['inputs'] = transaction['inputs'][0:1]
|
|
transaction['inputs'][0]['txid'] = 'txid' + (('6001' + str(i)) * 12)
|
|
transaction['inputs'][0]['index'] = 1
|
|
transaction['inputs'][0]['sequence'] = 2158510000 + (i * 1000)
|
|
for k, output in enumerate(transaction['outputs'], start=1):
|
|
output['scriptPubKey'] = 'scriptpubkey' + ((f"{i:02}" + f"{k:02}") * 14)
|
|
output['index'] = k
|
|
output['amount_msat'] = 201998900000 + (i * 1000) + (k * 100)
|
|
update_example(node=l1, method='listtransactions', params={}, response=listtransactions_res1)
|
|
listclosedchannels_res1 = l2.rpc.listclosedchannels()
|
|
listclosedchannels_res1 = update_list_responses(listclosedchannels_res1, list_key='closedchannels')
|
|
for i, closedchannel in enumerate(listclosedchannels_res1['closedchannels'], start=1):
|
|
closedchannel['last_commitment_fee_msat'] = 2894000 + (i * 1000)
|
|
closedchannel['last_commitment_txid'] = 'txidcloselastcommitment0' + (('0000' + str(i)) * 8)
|
|
closedchannel['last_stable_connection'] = NEW_VALUES_LIST['time_at_850']
|
|
closedchannel['alias'] = {'local': '12' + str(i) + 'x13' + str(i) + 'x14' + str(i), 'remote': '15' + str(i) + 'x16' + str(i) + 'x17' + str(i)}
|
|
update_example(node=l2, method='listclosedchannels', params={}, response=listclosedchannels_res1)
|
|
|
|
update_example(node=l2, method='listconfigs', params={'config': 'network'})
|
|
update_example(node=l2, method='listconfigs', params={'config': 'experimental-dual-fund'})
|
|
l2.rpc.jsonschemas = {}
|
|
listconfigs_res3 = l2.rpc.listconfigs()
|
|
listconfigs_res3['configs']['htlc-maximum-msat']['value_msat'] = NEW_VALUES_LIST['htlc_max_msat']
|
|
listconfigs_res3 = update_list_responses(listconfigs_res3, list_key='configs', slice_upto=len(listconfigs_res3['configs']), update_func=None, sort=True)
|
|
update_example(node=l2, method='listconfigs', params={}, response=listconfigs_res3)
|
|
|
|
update_example(node=l2, method='listsqlschemas', params={'table': 'offers'})
|
|
update_example(node=l2, method='listsqlschemas', params=['closedchannels'])
|
|
|
|
listpeerchannels_res1 = l1.rpc.listpeerchannels(l2.info['id'])
|
|
listpeerchannels_res1 = update_list_responses(listpeerchannels_res1, list_key='channels', slice_upto=3)
|
|
for i, channel in enumerate(listpeerchannels_res1['channels'], start=1):
|
|
channel['last_stable_connection'] = NEW_VALUES_LIST['time_at_850'] + (i * 10000)
|
|
channel['scratch_txid'] = 'scratchid1' + (('0' + str(i)) * 27)
|
|
channel['alias']['local'] = '3000000' + str(i) + 'x6000000' + str(i) + 'x6000' + str(i)
|
|
channel['alias']['remote'] = '1000000' + str(i) + 'x2000000' + str(i) + 'x3000' + str(i)
|
|
channel['max_total_htlc_in_msat'] = NEW_VALUES_LIST['htlc_max_msat']
|
|
for j, state in enumerate(channel['state_changes'], start=1):
|
|
state['timestamp'] = '2024-10-10T00:0' + str(j) + ':00.000Z'
|
|
update_example(node=l1, method='listpeerchannels', params={'id': l2.info['id']}, response=listpeerchannels_res1)
|
|
listpeerchannels_res2 = l1.rpc.listpeerchannels()
|
|
listpeerchannels_2 = None
|
|
listpeerchannels_3 = None
|
|
i = 0
|
|
for channel in listpeerchannels_res2['channels']:
|
|
if channel['peer_id'] == l2.info['id'] or channel['peer_id'] == l3.info['id']:
|
|
i = 2 if channel['peer_id'] == l2.info['id'] else 3
|
|
scrt_id = 'scratchid2' + (('0' + str(i)) * 27)
|
|
channel['last_stable_connection'] = NEW_VALUES_LIST['time_at_850'] + (i * 10000)
|
|
channel['scratch_txid'] = scrt_id
|
|
channel['alias']['local'] = '3000000' + str(i) + 'x6000000' + str(i) + 'x6000' + str(i)
|
|
channel['alias']['remote'] = '1000000' + str(i) + 'x2000000' + str(i) + 'x3000' + str(i)
|
|
channel['close_to_addr'] = 'bcrt1pcl' + (('000' + str(i)) * 14)
|
|
channel['close_to'] = 'db2dec31' + (('0' + str(i)) * 30)
|
|
channel['status'][0] = re.sub(r'(tx:)[a-f0-9]+', r'\1' + scrt_id, channel['status'][0])
|
|
channel['max_total_htlc_in_msat'] = NEW_VALUES_LIST['htlc_max_msat']
|
|
if 'inflight' in channel and len(channel['inflight']) > 0:
|
|
channel['inflight'][0]['scratch_txid'] = scrt_id
|
|
for j, state in enumerate(channel['state_changes'], start=1):
|
|
state['timestamp'] = '2024-10-10T00:0' + str(j) + ':00.000Z'
|
|
if channel['peer_id'] == l2.info['id']:
|
|
listpeerchannels_2 = channel
|
|
else:
|
|
listpeerchannels_3 = channel
|
|
listpeerchannels_res2['channels'] = [channel for channel in [listpeerchannels_2, listpeerchannels_3] if channel is not None]
|
|
update_example(node=l1, method='listpeerchannels', params={}, response=listpeerchannels_res2)
|
|
|
|
listchannels_res1 = l1.rpc.listchannels(c12)
|
|
listchannels_res1 = update_list_responses(listchannels_res1, list_key='channels', slice_upto=5, update_func=lambda x, i: x.update({'last_update': NEW_VALUES_LIST['time_at_850'] + (i * 10000), 'channel_flags': i, 'active': i % 2 == 0}))
|
|
update_example(node=l1, method='listchannels', params={'short_channel_id': c12}, response=listchannels_res1)
|
|
listchannels_res2 = l1.rpc.listchannels()
|
|
listchannels_res2 = update_list_responses(listchannels_res2, list_key='channels', slice_upto=5, update_func=lambda x, i: x.update({'last_update': NEW_VALUES_LIST['time_at_850'] + (i * 10000), 'channel_flags': i, 'active': i % 2 == 0}))
|
|
update_example(node=l1, method='listchannels', params={}, response=listchannels_res2)
|
|
|
|
listnodes_res1 = l2.rpc.listnodes(l3.info['id'])
|
|
listnodes_res1 = update_list_responses(listnodes_res1, list_key='nodes', slice_upto=5, update_func=lambda x, i: x.update({'last_timestamp': NEW_VALUES_LIST['time_at_800'] + (i * 10000)}))
|
|
update_example(node=l2, method='listnodes', params={'id': l3.info['id']}, response=listnodes_res1)
|
|
listnodes_res2 = l2.rpc.listnodes()
|
|
listnodes_res2 = update_list_responses(listnodes_res2, list_key='nodes', slice_upto=5, update_func=lambda x, i: x.update({'last_timestamp': NEW_VALUES_LIST['time_at_800'] + (i * 10000)}))
|
|
update_example(node=l2, method='listnodes', params={}, response=listnodes_res2)
|
|
|
|
listpeers_res1 = l2.rpc.listpeers(l3.info['id'])
|
|
listpeers_res1 = update_list_responses(listpeers_res1, list_key='peers', slice_upto=5, update_func=None, sort=True, sort_key='id')
|
|
update_example(node=l2, method='listpeers', params={'id': l3.info['id']}, response=listpeers_res1)
|
|
listpeers_res2 = l2.rpc.listpeers()
|
|
listpeers_res2 = update_list_responses(listpeers_res2, list_key='peers', slice_upto=5, update_func=None, sort=True, sort_key='id')
|
|
update_example(node=l2, method='listpeers', params={}, response=listpeers_res2)
|
|
|
|
update_example(node=l2, method='listdatastore', params={'key': ['employee']})
|
|
update_example(node=l2, method='listdatastore', params={'key': 'somekey'})
|
|
|
|
listoffers_res1 = l2.rpc.listoffers(active_only=True)
|
|
for i, offer in enumerate(listoffers_res1['offers'], start=1):
|
|
ofr_id = 'offerid_l2' + str(i)
|
|
bolt12_id = 'bolt12_l2' + str(i)
|
|
offer['offer_id'] = NEW_VALUES_LIST[ofr_id]
|
|
offer['bolt12'] = NEW_VALUES_LIST[bolt12_id]
|
|
listoffers_res1 = update_list_responses(listoffers_res1, list_key='offers', slice_upto=5, update_func=None, sort=True, sort_key='offer_id')
|
|
update_example(node=l2, method='listoffers', params={'active_only': True}, response=listoffers_res1)
|
|
listoffers_res2 = l2.rpc.listoffers(offer_id=offer_l23['offer_id'])
|
|
listoffers_res2 = update_list_responses(listoffers_res2, list_key='offers')
|
|
update_example(node=l2, method='listoffers', params=[offer_l23['offer_id']], response=listoffers_res2)
|
|
|
|
update_example(node=l2, method='listinvoicerequests', params=[inv_req_l1_l22['invreq_id']])
|
|
listinvoicerequests_res2 = l2.rpc.listinvoicerequests()
|
|
listinvoicerequests_res2 = update_list_responses(listinvoicerequests_res2, list_key='invoicerequests', slice_upto=len(listinvoicerequests_res2['invoicerequests']), update_func=None, sort=True, sort_key='used')
|
|
update_example(node=l2, method='listinvoicerequests', params={}, response=listinvoicerequests_res2)
|
|
update_example(node=l2, method='listaddresses', params=[address_l22['p2tr']])
|
|
update_example(node=l2, method='listaddresses', params={'start': 6, 'limit': 2})
|
|
REPLACE_RESPONSE_VALUES.extend([
|
|
{'data_keys': ['any', 'invreq_id'], 'original_value': inv_req_l1_l22['invreq_id'], 'new_value': NEW_VALUES_LIST['invreq_id_l1_l22']},
|
|
{'data_keys': ['netaddr'], 'original_value': listpeers_res2['peers'][0]['netaddr'], 'new_value': [NEW_VALUES_LIST['l1_addr']]},
|
|
{'data_keys': ['any'], 'original_value': listconfigs_res3['configs']['addr']['values_str'][0], 'new_value': NEW_VALUES_LIST['configs_3_addr2']},
|
|
{'data_keys': ['value_int'], 'original_value': listconfigs_res3['configs']['bitcoin-rpcport']['value_int'], 'new_value': NEW_VALUES_LIST['bitcoin-rpcport']},
|
|
{'data_keys': ['value_int'], 'original_value': listconfigs_res3['configs']['grpc-port']['value_int'], 'new_value': NEW_VALUES_LIST['grpc-port']},
|
|
{'data_keys': ['value_str'], 'original_value': listconfigs_res3['configs']['alias']['value_str'], 'new_value': NEW_VALUES_LIST['l2_alias']},
|
|
{'data_keys': ['channel_flags'], 'original_value': listchannels_res2['channels'][-1]['channel_flags'], 'new_value': 2},
|
|
])
|
|
logger.info('Lists Done!')
|
|
except Exception as e:
|
|
logger.error(f'Error in generating lists examples: {e}')
|
|
raise
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def setup_logging():
|
|
global logger
|
|
logger.setLevel(logging.DEBUG)
|
|
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s", "%H:%M:%S")
|
|
stream_handler = logging.StreamHandler()
|
|
stream_handler.setFormatter(formatter)
|
|
logger.addHandler(stream_handler)
|
|
file_handler = logging.FileHandler(LOG_FILE)
|
|
file_handler.setFormatter(formatter)
|
|
logger.addHandler(file_handler)
|
|
|
|
|
|
@unittest.skipIf(not GENERATE_EXAMPLES, 'Generates examples for doc/schema/lightning-*.json files.')
|
|
def test_generate_examples(node_factory, bitcoind, executor):
|
|
"""Re-generates examples for doc/schema/lightning-*.json files"""
|
|
try:
|
|
global ALL_RPC_EXAMPLES, REGENERATING_RPCS
|
|
|
|
def list_all_examples():
|
|
"""list all methods used in 'update_example' calls to ensure that all methods are covered"""
|
|
try:
|
|
global REGENERATING_RPCS
|
|
methods = []
|
|
file_path = os.path.abspath(__file__)
|
|
|
|
# Parse and traverse this file's content to list all methods & file names
|
|
with open(file_path, "r") as file:
|
|
file_content = file.read()
|
|
tree = ast.parse(file_content)
|
|
for node in ast.walk(tree):
|
|
if isinstance(node, ast.Call) and isinstance(node.func, ast.Name) and node.func.id == 'update_example':
|
|
for keyword in node.keywords:
|
|
if (keyword.arg == 'method' and isinstance(keyword.value, ast.Constant)):
|
|
if keyword.value.value not in methods:
|
|
methods.append(keyword.value.value)
|
|
return methods
|
|
except Exception as e:
|
|
logger.error(f'Error in listing all examples: {e}')
|
|
raise
|
|
|
|
def list_missing_examples():
|
|
"""Checks for missing example & log an error if missing."""
|
|
try:
|
|
global ALL_RPC_EXAMPLES
|
|
missing_examples = ''
|
|
for file_name in os.listdir('doc/schemas'):
|
|
if not file_name.endswith('.json'):
|
|
continue
|
|
file_name_str = str(file_name).replace('lightning-', '').replace('.json', '')
|
|
# Log an error if the method is not in the list
|
|
if file_name_str not in ALL_RPC_EXAMPLES and file_name_str not in IGNORE_RPCS_LIST:
|
|
missing_examples = missing_examples + f"'{file_name_str}', "
|
|
if missing_examples != '':
|
|
raise MissingExampleError(f"Missing {missing_examples.count(', ')} Examples For: [{missing_examples.rstrip(', ')}]")
|
|
except MissingExampleError:
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f'Error in listing missing examples: {e}')
|
|
raise
|
|
|
|
ALL_RPC_EXAMPLES = list_all_examples()
|
|
logger.info(f'This test can reproduce examples for {len(ALL_RPC_EXAMPLES)} methods: {ALL_RPC_EXAMPLES}')
|
|
logger.warning(f'This test ignores {len(IGNORE_RPCS_LIST)} rpc methods: {IGNORE_RPCS_LIST}')
|
|
REGENERATING_RPCS = [rpc.strip() for rpc in os.getenv("REGENERATE").split(', ')] if os.getenv("REGENERATE") else ALL_RPC_EXAMPLES
|
|
list_missing_examples()
|
|
l1, l2, l3, l4, l5, l6, c12, c23, c25 = setup_test_nodes(node_factory, bitcoind)
|
|
c23_2, c23res2, c34_2, inv_l11, inv_l21, inv_l22, inv_l31, inv_l32, inv_l34 = generate_transactions_examples(l1, l2, l3, l4, l5, c25, bitcoind)
|
|
rune_l21 = generate_runes_examples(l1, l2, l3)
|
|
generate_datastore_examples(l2)
|
|
generate_bookkeeper_examples(l2, l3, c23res2['channel_id'])
|
|
offer_l23, inv_req_l1_l22 = generate_offers_renepay_examples(l1, l2, inv_l21, inv_l34)
|
|
generate_askrene_examples(l1, l2, l3, c12, c23_2)
|
|
generate_wait_examples(l1, l2, bitcoind, executor)
|
|
address_l22 = generate_utils_examples(l1, l2, l3, l4, l5, l6, c23_2, c34_2, inv_l11, inv_l22, rune_l21, bitcoind)
|
|
generate_splice_examples(node_factory, bitcoind)
|
|
generate_channels_examples(node_factory, bitcoind, l1, l3, l4, l5)
|
|
generate_autoclean_delete_examples(l1, l2, l3, l4, l5, c12, c23)
|
|
generate_backup_recovery_examples(node_factory, l4, l5, l6)
|
|
generate_list_examples(l1, l2, l3, c12, c23_2, inv_l31, inv_l32, offer_l23, inv_req_l1_l22, address_l22)
|
|
update_examples_in_schema_files()
|
|
logger.info('All Done!!!')
|
|
except Exception as e:
|
|
logger.error(e, exc_info=True)
|
|
sys.exit(1)
|