Skip to content
a mock of the c-lightning interface for presenting collections of invoices in various lifecycle states
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
lightning_payencode
.gitignore
README.md
daemon.py
mock_c_lightning.py
requirements.txt

README.md

Mock of C-Lightning Invoicing

This is a utility that will generate fake BOLT11 invoices in the manner of the c-lightning command line interface. It is stateful in that it will list issued invoices.

The objective is to enable regression/unit testing of application code that is driven by issued, paid and expired invoices.

Once an invoice is issued, the time can be 'advanced' with the advancetimestamp command such that invoices are appropriately treated as 'expired' without having to wait.

Also, an invoice can be marked paid with the markpaid command and they will be subsequently listed as paid.

This is a very simple implementation, more fleshed-out feature are easy to imagine, but this is the minimal necessary for my app's needs at present.

Example Use (CLI)

Output Usage

$ ./mock_c_lightning.py -h
usage: mock_c_lightning.py [-h]
                           {invoice,listinvoices,autocleaninvoice,delinvoice,markpaid,advancetime,reset}
                           ...

mock c-lightning

positional arguments:
  {invoice,listinvoices,autocleaninvoice,delinvoice,markpaid,advancetime,reset}
                        sub-command help
    invoice             Create an invoice for {msatoshi} with {label} and
                        {description} with optional {expiry} seconds (default
                        1 hour) and optional {preimage} (default
                        autogenerated)
    listinvoices        list all invoices
    autocleaninvoice    autocleaninvoice help
    delinvoice          Delete invoice {label} with {status}
    markpaid            mark invoice as paid
    advancetime         advance the system clock to make invoices expire
                        sooner
    reset               reset the invoice state

optional arguments:
  -h, --help            show this help message and exit

Note - this is far from an exact replica of lightning-cli

List invoices

$ ./mock_c_lightning.py listinvoices
[]

Issue invoices and list

$ ./mock_c_lightning.py invoice 1000 myLabel1 "my description of the first invoice" 3600 5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03
{
  "bolt11": "lnbc10n1pduy53dpp5ajm9hwv0nkg9kuz93xrv887t44m3te0jlnpmrurhvltus03y8rxqdpcd4ujqer9wd3hy6tsw35k7m3qdanzqargv5sxv6tjwd6zq6twwehkjcm9xqrrssdnllrzc0mr0h3qay2knvxes2h23vjhq3vl4yld5zynmcsdlk2ms8lh78wvu656k7x63626ttpqjwuzzp3lsy7n5acakqa5t4ln4293qqud8wus",
  "expires_at": 1539465277,
  "expiry_time": 1539465277,
  "payment_hash": "ecb65bb98f9d905b70458986c39fcbad7715e5f2fcc3b1f07767d7c83e2438cc"
}
$ ./mock_c_lightning.py invoice 1000 myLabel2 "my description of the second invoice" 3600 e258d248fda94c63753607f7c4494ee0fcbe92f1a76bfdac795c9d84101eb317
{
  "bolt11": "lnbc10n1pduy5jlpp5ms986sz8auale8e2smwzwrnwvl9h5wnuqudvah6cnyuz7czq6yrqdp6d4ujqer9wd3hy6tsw35k7m3qdanzqargv5s8xetrdahxggrfdemx76trv5xqrrss6yh8s99j8ze9s6p9aqv2gwmv9pm26mdeq8waf7a3xjx2728zyjt9jjk8znxksuwglvzf9pyn3vjp820m7ncguztfjleeum6gcd8satgqqnpaxt",
  "expires_at": 1539465327,
  "expiry_time": 1539465327,
  "payment_hash": "dc0a7d4047ef3bfc9f2a86dc270e6e67cb7a3a7c071acedf5899382f6040d106"
}
$ ./mock_c_lightning.py listinvoices
[
  {
    "bolt11": "lnbc10n1pduy53dpp5ajm9hwv0nkg9kuz93xrv887t44m3te0jlnpmrurhvltus03y8rxqdpcd4ujqer9wd3hy6tsw35k7m3qdanzqargv5sxv6tjwd6zq6twwehkjcm9xqrrssdnllrzc0mr0h3qay2knvxes2h23vjhq3vl4yld5zynmcsdlk2ms8lh78wvu656k7x63626ttpqjwuzzp3lsy7n5acakqa5t4ln4293qqud8wus",
    "expires_at": 1539465277,
    "expiry_time": 1539465277,
    "label": "myLabel1",
    "msatoshi": 1000,
    "payment_hash": "ecb65bb98f9d905b70458986c39fcbad7715e5f2fcc3b1f07767d7c83e2438cc",
    "status": "unpaid"
  },
  {
    "bolt11": "lnbc10n1pduy5jlpp5ms986sz8auale8e2smwzwrnwvl9h5wnuqudvah6cnyuz7czq6yrqdp6d4ujqer9wd3hy6tsw35k7m3qdanzqargv5s8xetrdahxggrfdemx76trv5xqrrss6yh8s99j8ze9s6p9aqv2gwmv9pm26mdeq8waf7a3xjx2728zyjt9jjk8znxksuwglvzf9pyn3vjp820m7ncguztfjleeum6gcd8satgqqnpaxt",
    "expires_at": 1539465327,
    "expiry_time": 1539465327,
    "label": "myLabel2",
    "msatoshi": 1000,
    "payment_hash": "dc0a7d4047ef3bfc9f2a86dc270e6e67cb7a3a7c071acedf5899382f6040d106",
    "status": "unpaid"
  }
]

Mark one paid and advance time to make the other expire and then list

$ ./mock_c_lightning.py markpaid myLabel2
$ ./mock_c_lightning.py advancetime 10000
$ ./mock_c_lightning.py listinvoices
[
  {
    "bolt11": "lnbc10n1pduy53dpp5ajm9hwv0nkg9kuz93xrv887t44m3te0jlnpmrurhvltus03y8rxqdpcd4ujqer9wd3hy6tsw35k7m3qdanzqargv5sxv6tjwd6zq6twwehkjcm9xqrrssdnllrzc0mr0h3qay2knvxes2h23vjhq3vl4yld5zynmcsdlk2ms8lh78wvu656k7x63626ttpqjwuzzp3lsy7n5acakqa5t4ln4293qqud8wus",
    "expires_at": 1539465277,
    "expiry_time": 1539465277,
    "label": "myLabel1",
    "msatoshi": 1000,
    "payment_hash": "ecb65bb98f9d905b70458986c39fcbad7715e5f2fcc3b1f07767d7c83e2438cc",
    "status": "expired"
  },
  {
    "bolt11": "lnbc10n1pduy5jlpp5ms986sz8auale8e2smwzwrnwvl9h5wnuqudvah6cnyuz7czq6yrqdp6d4ujqer9wd3hy6tsw35k7m3qdanzqargv5s8xetrdahxggrfdemx76trv5xqrrss6yh8s99j8ze9s6p9aqv2gwmv9pm26mdeq8waf7a3xjx2728zyjt9jjk8znxksuwglvzf9pyn3vjp820m7ncguztfjleeum6gcd8satgqqnpaxt",
    "expires_at": 1539465327,
    "expiry_time": 1539465327,
    "label": "myLabel2",
    "msatoshi": 1000,
    "msatoshi_recieved": 1033,
    "paid_at": 1539461783,
    "paid_timestamp": 1539461783,
    "pay_index": 1,
    "payment_hash": "dc0a7d4047ef3bfc9f2a86dc270e6e67cb7a3a7c071acedf5899382f6040d106",
    "status": "paid"
  }
]

Clean up

$ ./mock_c_lightning.py delinvoice myLabel1 expired
$ ./mock_c_lightning.py delinvoice myLabel2 paid
$ ./mock_c_lightning.py listinvoices
[]

Programmatic use

The module daemon.py provides example classes CliMockDaemon, MemMockDaemon and RealDaemon that illustrate how this can be integrated into a program. Each implement the interface of the Daemon superclass.

CliMockDamon

This interfaces with this utility via a subprocess shell-out. This is good for observing the state of the daemon on your own, but has the overhead of shelling out to the console and reading/writing from an on-disk JSON database, so it can be slower than MemMockDaemon

MemMockDamon

This instantiates the mock daemon and database as an in-memory object. This is faster for doing many invoices quickly (such as in a rapid-fire unit test), but doesn't provide a CLI interface for checking up on it.

RealDaemon

This interfaces with the real c-lightning daemon via the pylightning module that uses the RPC port.

Dependencies

This app uses code from https://github.com/rustyrussell/lightning-payencode to encode BOLT11 invoices, and hence has the same dependencies to be installed via pip3.

License

None yet, but mainly because lightining-payencode is not yet licensed. The intention is to follow along with what is chosen for that project. FWIW, The author of this project prefers MIT licences for this type of thing.

You can’t perform that action at this time.