Browse Source

daemon/lightningd: remove building, and main files

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 7 years ago
committed by Christian Decker
parent
commit
88bb38f63b
  1. 6
      .travis.yml
  2. 4
      INSTALL.md
  3. 6
      Makefile
  4. 2
      contrib/pylightning/lightning/__init__.py
  5. 95
      contrib/pylightning/lightning/lightning.py
  6. 62
      daemon/Makefile
  7. 1
      daemon/chaintopology.c
  8. 359
      daemon/channel.c
  9. 140
      daemon/channel.h
  10. 225
      daemon/commit_tx.c
  11. 40
      daemon/commit_tx.h
  12. 656
      daemon/cryptopkt.c
  13. 48
      daemon/cryptopkt.h
  14. 1980
      daemon/db.c
  15. 76
      daemon/db.h
  16. 2
      daemon/dns.c
  17. 40
      daemon/failure.c
  18. 36
      daemon/failure.h
  19. 144
      daemon/feechange.c
  20. 52
      daemon/feechange.h
  21. 23
      daemon/feechange_state.h
  22. 81
      daemon/htlc.c
  23. 9
      daemon/invoice.c
  24. 280
      daemon/irc_announce.c
  25. 9
      daemon/irc_announce.h
  26. 4
      daemon/jsonrpc.c
  27. 174
      daemon/lightningd.c
  28. 36
      daemon/names.c
  29. 10
      daemon/names.h
  30. 80
      daemon/output_to_htlc.c
  31. 20
      daemon/output_to_htlc.h
  32. 231
      daemon/p2p_announce.c
  33. 15
      daemon/p2p_announce.h
  34. 599
      daemon/packets.c
  35. 478
      daemon/pay.c
  36. 19
      daemon/pay.h
  37. 5294
      daemon/peer.c
  38. 91
      daemon/peer.h
  39. 210
      daemon/peer_internal.h
  40. 169
      daemon/routingrpc.c
  41. 251
      daemon/secrets.c
  42. 68
      daemon/secrets.h
  43. 479
      daemon/sphinx.c
  44. 136
      daemon/sphinx.h
  45. 77
      daemon/state.h
  46. 99
      daemon/state_types.h
  47. 73
      daemon/test/Makefile
  48. 52
      daemon/test/run-maxfee.c
  49. 21
      daemon/test/scripts/generate-block.sh
  50. 29
      daemon/test/scripts/getinput.sh
  51. 467
      daemon/test/scripts/helpers.sh
  52. 47
      daemon/test/scripts/setup.sh
  53. 11
      daemon/test/scripts/shutdown.sh
  54. 40
      daemon/test/scripts/vars.sh
  55. 359
      daemon/test/test-basic
  56. 86
      daemon/test/test-different-fees
  57. 82
      daemon/test/test-funding-timeout
  58. 87
      daemon/test/test-invoice
  59. 96
      daemon/test/test-mutual-close-with-htlcs
  60. 146
      daemon/test/test-routing
  61. 91
      daemon/test/test-steal
  62. 87
      daemon/test/test-unilateral
  63. 144
      daemon/wallet.c
  64. 21
      daemon/wallet.h
  65. 4
      daemon/watch.c
  66. 151
      tests/test_lightningd.py
  67. 13
      tests/utils.py
  68. 3
      type_to_string.c

6
.travis.yml

@ -3,12 +3,12 @@ dist: trusty
sudo: true sudo: true
env: env:
- NOVALGRIND=1 NO_VALGRIND=0 - NOVALGRIND=1
- NOVALGRIND=0 NO_VALGRIND=1 - NOVALGRIND=0
# Trusty (aka 14.04) is way way too old, so run in docker... # Trusty (aka 14.04) is way way too old, so run in docker...
script: script:
- docker pull cdecker/lightning-ci > /dev/null - docker pull cdecker/lightning-ci > /dev/null
- docker run --rm=true -v "${TRAVIS_BUILD_DIR}":/build -t cdecker/lightning-ci make -j3 - docker run --rm=true -v "${TRAVIS_BUILD_DIR}":/build -t cdecker/lightning-ci make -j3
- docker run --rm=true -e NOVALGRIND=${NOVALGRIND:-0} -e TEST_DEBUG=${TEST_DEBUG:-0} -e NO_VALGRIND=${NOVALGRIND:-0} -v "${TRAVIS_BUILD_DIR}":/build -t cdecker/lightning-ci make check - docker run --rm=true -e NOVALGRIND=${NOVALGRIND:-0} -e TEST_DEBUG=${TEST_DEBUG:-0} -v "${TRAVIS_BUILD_DIR}":/build -t cdecker/lightning-ci make check
- docker run --rm=true -v "${TRAVIS_BUILD_DIR}":/build -t cdecker/lightning-ci make check-source - docker run --rm=true -v "${TRAVIS_BUILD_DIR}":/build -t cdecker/lightning-ci make check-source

4
INSTALL.md

@ -51,7 +51,7 @@ make
Running lightning: Running lightning:
``` ```
bitcoind & bitcoind &
./daemon/lightningd & ./lightningd/lightningd &
./daemon/lightning-cli help ./daemon/lightning-cli help
``` ```
**Note**: You may need to include `testnet=1` in `bitcoin.conf` **Note**: You may need to include `testnet=1` in `bitcoin.conf`
@ -85,6 +85,6 @@ Running lightning:
``` ```
bitcoind bitcoind
export LD_LIBRARY_PATH=/usr/local/lib export LD_LIBRARY_PATH=/usr/local/lib
./daemon/lightningd ./lightningd/lightningd
./daemon/lightning-cli help ./daemon/lightning-cli help
``` ```

6
Makefile

@ -219,7 +219,7 @@ CFLAGS := $(CWARNFLAGS) $(CDEBUGFLAGS) -I $(CCANDIR) -I libwally-core/src/secp25
LDLIBS := -lprotobuf-c -lgmp -lsqlite3 $(COVFLAGS) LDLIBS := -lprotobuf-c -lgmp -lsqlite3 $(COVFLAGS)
$(PROGRAMS): CFLAGS+=-I. $(PROGRAMS): CFLAGS+=-I.
default: $(PROGRAMS) doc-all daemon-all default: $(PROGRAMS) doc-all
include doc/Makefile include doc/Makefile
include bitcoin/Makefile include bitcoin/Makefile
@ -242,7 +242,7 @@ test-protocol: test/test_protocol
check: test-protocol check: test-protocol
$(MAKE) pytest $(MAKE) pytest
pytest: daemon/lightningd daemon/lightning-cli lightningd-all pytest: daemon/lightning-cli lightningd-all
PYTHONPATH=contrib/pylightning python3 tests/test_lightningd.py -f PYTHONPATH=contrib/pylightning python3 tests/test_lightningd.py -f
# Keep includes in alpha order. # Keep includes in alpha order.
@ -255,7 +255,7 @@ check-hdr-include-order/%: %
@if [ "$$(grep '^#include' < $< | tail -n +2)" != "$$(grep '^#include' < $< | tail -n +2 | LC_ALL=C sort)" ]; then echo "$<:1: includes out of order"; exit 1; fi @if [ "$$(grep '^#include' < $< | tail -n +2)" != "$$(grep '^#include' < $< | tail -n +2 | LC_ALL=C sort)" ]; then echo "$<:1: includes out of order"; exit 1; fi
# Make sure Makefile includes all headers. # Make sure Makefile includes all headers.
check-makefile: check-daemon-makefile check-makefile:
@if [ "`echo bitcoin/*.h`" != "$(BITCOIN_HEADERS)" ]; then echo BITCOIN_HEADERS incorrect; exit 1; fi @if [ "`echo bitcoin/*.h`" != "$(BITCOIN_HEADERS)" ]; then echo BITCOIN_HEADERS incorrect; exit 1; fi
@if [ x"`ls *.h | grep -v ^gen_ | fgrep -v lightning.pb-c.h`" != x"`echo $(CORE_HEADERS) $(CORE_TX_HEADERS) | tr ' ' '\n' | LC_ALL=C sort`" ]; then echo CORE_HEADERS incorrect; exit 1; fi @if [ x"`ls *.h | grep -v ^gen_ | fgrep -v lightning.pb-c.h`" != x"`echo $(CORE_HEADERS) $(CORE_TX_HEADERS) | tr ' ' '\n' | LC_ALL=C sort`" ]; then echo CORE_HEADERS incorrect; exit 1; fi
@if [ x"$(CCANDIR)/config.h `find $(CCANDIR)/ccan -name '*.h' | grep -v /test/ | LC_ALL=C sort | tr '\n' ' '`" != x"$(CCAN_HEADERS) " ]; then echo CCAN_HEADERS incorrect; exit 1; fi @if [ x"$(CCANDIR)/config.h `find $(CCANDIR)/ccan -name '*.h' | grep -v /test/ | LC_ALL=C sort | tr '\n' ' '`" != x"$(CCAN_HEADERS) " ]; then echo CCAN_HEADERS incorrect; exit 1; fi

2
contrib/pylightning/lightning/__init__.py

@ -1 +1 @@
from .lightning import LightningRpc, LegacyLightningRpc from .lightning import LightningRpc

95
contrib/pylightning/lightning/lightning.py

@ -105,101 +105,6 @@ class LightningRpc(UnixDomainSocketRpc):
return self._call("dev-add-route", [src, dst, base, var, delay, minblocks]) return self._call("dev-add-route", [src, dst, base, var, delay, minblocks])
class LegacyLightningRpc(UnixDomainSocketRpc):
def getchannels(self):
"""List all known channels.
"""
return self._call("getchannels", [])['channels']
def getnodes(self):
"""List all known nodes in the network.
"""
return self._call("getnodes", [])
def getlog(self, level=None):
"""Get logs, with optional level: [io|debug|info|unusual]
"""
return self._call("getlog", [level])
def getpeers(self):
"""Return a list of peers.
"""
return self._call("getpeers", [])
def getroute(self, destination, amount, riskfactor=1):
"""Return route to `destination` for `amount` milli satoshis, using `riskfactor`
"""
return self._call("getroute", [destination, amount, riskfactor])['route']
def getinfo(self):
"""Get general information about this node"""
return self._call("getinfo", [])
def invoice(self, amount, label, paymentKey=None):
"""Create a new invoice.
Create invoice for `amount` millisatoshi with
`label`. Optionally you can specify the `paymentKey`,
otherwise a random one will be generated. The `label` has to
be unique.
"""
args = [amount, label]
if paymentKey is not None:
args.append(paymentKey)
return self._call("invoice", args)
def waitinvoice(self, label=None, async=False):
"""Wait for the next invoice to be paid, after `label` (if supplied)
"""
args = []
if label is not None:
args.append(label)
def call():
return self._call("waitinvoice", args)
if async:
return self.executor.submit(call)
else:
return call()
def sendpay(self, route, paymenthash):
"""Send along `route` in return for preimage of `paymenthash`
"""
return self._call("sendpay", [route, paymenthash])
def pay(self, destination, amount, paymenthash):
"""Shorthand for `getroute` and `sendpay`
Sends `amount` millisatoshi to `destination` for invoice matching `paymenthash`
"""
route = self.getroute(destination, amount, 1)
return self.sendpay(route, paymenthash)
def dev_rhash(self, secret):
res = self._call("dev-rhash", [secret])
print(res)
return self._call("dev-rhash", [secret])['rhash']
def dev_newhtlc(self, peerid, amount, expiry, rhash):
return self._call("dev-newhtlc", [peerid, amount, expiry, rhash])
def dev_add_route(self, src, dst, base_fee, fee_rate, delay, minblocks):
return self._call("dev-add-route", [src, dst, base_fee, fee_rate, delay, minblocks])
def connect(self, hostname, port, fundingtxhex, async=False):
"""Connect to a `host` at `port` using `fundingtxhex` to fund
"""
def call_connect():
return self._call("connect", [hostname, port, fundingtxhex])
if not async:
return call_connect()
else:
return self.executor.submit(call_connect)
def newaddr(self):
"""Get a new address to fund a channel
"""
return self._call("newaddr", [])
if __name__ == "__main__": if __name__ == "__main__":
l1 = LightningRpc("/tmp/lightning1/lightning-rpc") l1 = LightningRpc("/tmp/lightning1/lightning-rpc")

62
daemon/Makefile

@ -8,7 +8,7 @@ LC_CTYPE=C
daemon-wrongdir: daemon-wrongdir:
$(MAKE) -C .. daemon-all $(MAKE) -C .. daemon-all
daemon-all: daemon/lightningd daemon/lightning-cli daemon-all: daemon/lightning-cli
DAEMON_LIB_SRC := \ DAEMON_LIB_SRC := \
daemon/configdir.c \ daemon/configdir.c \
@ -21,35 +21,16 @@ DAEMON_SRC := \
daemon/bitcoind.c \ daemon/bitcoind.c \
daemon/broadcast.c \ daemon/broadcast.c \
daemon/chaintopology.c \ daemon/chaintopology.c \
daemon/channel.c \
daemon/commit_tx.c \
daemon/cryptopkt.c \
daemon/db.c \
daemon/dns.c \ daemon/dns.c \
daemon/failure.c \
daemon/feechange.c \
daemon/htlc.c \
daemon/htlc_state.c \ daemon/htlc_state.c \
daemon/invoice.c \ daemon/invoice.c \
daemon/irc_announce.c \
daemon/jsonrpc.c \ daemon/jsonrpc.c \
daemon/lightningd.c \
daemon/netaddr.c \ daemon/netaddr.c \
daemon/options.c \ daemon/options.c \
daemon/opt_time.c \ daemon/opt_time.c \
daemon/output_to_htlc.c \
daemon/p2p_announce.c \
daemon/packets.c \
daemon/pay.c \
daemon/peer.c \
daemon/routing.c \ daemon/routing.c \
daemon/routingrpc.c \
daemon/secrets.c \
daemon/sphinx.c \
daemon/timeout.c \ daemon/timeout.c \
daemon/wallet.c \
daemon/watch.c \ daemon/watch.c \
daemon/names.c \
irc.c irc.c
DAEMON_OBJS := $(DAEMON_SRC:.c=.o) DAEMON_OBJS := $(DAEMON_SRC:.c=.o)
@ -61,50 +42,28 @@ DAEMON_JSMN_OBJS := daemon/jsmn.o
DAEMON_JSMN_HEADERS := daemon/jsmn/jsmn.h DAEMON_JSMN_HEADERS := daemon/jsmn/jsmn.h
DAEMON_GEN_HEADERS := \ DAEMON_GEN_HEADERS := \
daemon/gen_feechange_state_names.h \ daemon/gen_htlc_state_names.h
daemon/gen_htlc_state_names.h \
daemon/gen_pkt_names.h \
daemon/gen_state_names.h
DAEMON_HEADERS := \ DAEMON_HEADERS := \
daemon/bitcoind.h \ daemon/bitcoind.h \
daemon/broadcast.h \ daemon/broadcast.h \
daemon/chaintopology.h \ daemon/chaintopology.h \
daemon/channel.h \
daemon/commit_tx.h \
daemon/configdir.h \ daemon/configdir.h \
daemon/cryptopkt.h \
daemon/db.h \
daemon/dns.h \ daemon/dns.h \
daemon/failure.h \
daemon/feechange.h \
daemon/feechange_state.h \
daemon/htlc.h \ daemon/htlc.h \
daemon/htlc_state.h \ daemon/htlc_state.h \
daemon/invoice.h \ daemon/invoice.h \
daemon/irc_announce.h \
daemon/json.h \ daemon/json.h \
daemon/jsonrpc.h \ daemon/jsonrpc.h \
daemon/lightningd.h \ daemon/lightningd.h \
daemon/log.h \ daemon/log.h \
daemon/names.h \
daemon/netaddr.h \ daemon/netaddr.h \
daemon/opt_time.h \ daemon/opt_time.h \
daemon/options.h \ daemon/options.h \
daemon/output_to_htlc.h \
daemon/p2p_announce.h \
daemon/packets.h \ daemon/packets.h \
daemon/pay.h \
daemon/peer.h \
daemon/peer_internal.h \
daemon/pseudorand.h \ daemon/pseudorand.h \
daemon/routing.h \ daemon/routing.h \
daemon/secrets.h \
daemon/sphinx.h \
daemon/state.h \
daemon/state_types.h \
daemon/timeout.h \ daemon/timeout.h \
daemon/wallet.h \
daemon/watch.h daemon/watch.h
daemon/gen_htlc_state_names.h: daemon/htlc_state.h ccan/ccan/cdump/tools/cdump-enumstr daemon/gen_htlc_state_names.h: daemon/htlc_state.h ccan/ccan/cdump/tools/cdump-enumstr
@ -120,7 +79,7 @@ daemon/gen_state_names.h: daemon/state_types.h ccan/ccan/cdump/tools/cdump-enums
daemon/gen_pkt_names.h: lightning.pb-c.h ccan/ccan/cdump/tools/cdump-enumstr daemon/gen_pkt_names.h: lightning.pb-c.h ccan/ccan/cdump/tools/cdump-enumstr
(echo 'enum PktCase {'; grep '^ PKT__' lightning.pb-c.h; echo '};') | ccan/ccan/cdump/tools/cdump-enumstr - | sed 's/enum PktCase/Pkt__PktCase/' > $@ (echo 'enum PktCase {'; grep '^ PKT__' lightning.pb-c.h; echo '};') | ccan/ccan/cdump/tools/cdump-enumstr - | sed 's/enum PktCase/Pkt__PktCase/' > $@
$(DAEMON_OBJS) $(DAEMON_LIB_OBJS) $(DAEMON_CLI_OBJS): $(DAEMON_HEADERS) $(DAEMON_JSMN_HEADERS) $(BITCOIN_HEADERS) $(CORE_HEADERS) $(CORE_TX_HEADERS) $(GEN_HEADERS) $(DAEMON_GEN_HEADERS) $(CCAN_HEADERS) $(WIRE_HEADERS) $(WIRE_GEN_HEADERS) $(LIBSODIUM_HEADERS) $(LIBBASE58_HEADERS) $(DAEMON_LIB_OBJS) $(DAEMON_CLI_OBJS): $(DAEMON_JSMN_HEADERS) $(BITCOIN_HEADERS) $(CORE_HEADERS) $(CORE_TX_HEADERS) $(GEN_HEADERS) $(DAEMON_GEN_HEADERS) $(CCAN_HEADERS) $(WIRE_HEADERS) $(WIRE_GEN_HEADERS) $(LIBSODIUM_HEADERS) $(LIBBASE58_HEADERS)
$(DAEMON_JSMN_OBJS): $(DAEMON_JSMN_HEADERS) $(DAEMON_JSMN_OBJS): $(DAEMON_JSMN_HEADERS)
$(DAEMON_OBJS) $(DAEMON_LIB_OBJS) $(DAEMON_CLI_OBJS): CFLAGS += -USHACHAIN_BITS $(DAEMON_OBJS) $(DAEMON_LIB_OBJS) $(DAEMON_CLI_OBJS): CFLAGS += -USHACHAIN_BITS
@ -129,11 +88,6 @@ check-source: $(DAEMON_SRC:%=check-src-include-order/%)
check-source: $(DAEMON_LIB_SRC:%=check-src-include-order/%) check-source: $(DAEMON_LIB_SRC:%=check-src-include-order/%)
check-source: $(DAEMON_CLI_SRC:%=check-src-include-order/%) check-source: $(DAEMON_CLI_SRC:%=check-src-include-order/%)
check-source: $(DAEMON_HEADERS:%=check-hdr-include-order/%) check-source: $(DAEMON_HEADERS:%=check-hdr-include-order/%)
check-daemon-makefile:
@echo $(DAEMON_HEADERS) | tr ' ' '\012' > /tmp/daemon-headers-makefile
@ls daemon/*.h | grep -v daemon/gen > /tmp/daemon-headers-file
@if [ "`diff -w /tmp/daemon-headers-makefile /tmp/daemon-headers-file`" != "" ]; then echo DAEMON_HEADERS incorrect; diff -w --context=2 /tmp/daemon-headers-makefile /tmp/daemon-headers-file; exit 1; fi
@rm /tmp/daemon-headers-makefile /tmp/daemon-headers-file
check-source-bolt: $(DAEMON_SRC:%=bolt-check/%) $(DAEMON_HEADERS:%=bolt-check/%) check-source-bolt: $(DAEMON_SRC:%=bolt-check/%) $(DAEMON_HEADERS:%=bolt-check/%)
@ -152,17 +106,9 @@ daemon/jsmn/jsmn.c: daemon/jsmn/jsmn.h
daemon/jsmn.o: daemon/jsmn/jsmn.c daemon/jsmn.o: daemon/jsmn/jsmn.c
$(COMPILE.c) -DJSMN_STRICT=1 $(OUTPUT_OPTION) $< $(COMPILE.c) -DJSMN_STRICT=1 $(OUTPUT_OPTION) $<
# We need a 64-bit shachain (default)
daemon/shachain-64.o: $(CCANDIR)/ccan/crypto/shachain/shachain.c $(CCAN_HEADERS)
$(CC) $(CFLAGS) -USHACHAIN_BITS -c -o $@ $<
daemon/lightningd: $(DAEMON_OBJS) $(DAEMON_LIB_OBJS) $(DAEMON_JSMN_OBJS) $(CORE_OBJS) $(CORE_TX_OBJS) $(CORE_PROTOBUF_OBJS) $(BITCOIN_OBJS) $(LIBBASE58_OBJS) $(WIRE_OBJS) $(CCAN_OBJS) daemon/shachain-64.o libsecp256k1.a libsodium.a
daemon/lightning-cli: $(DAEMON_CLI_OBJS) $(DAEMON_LIB_OBJS) $(DAEMON_JSMN_OBJS) $(CORE_OBJS) $(BITCOIN_OBJS) $(LIBBASE58_OBJS) $(WIRE_OBJS) $(CCAN_OBJS) libsecp256k1.a libsodium.a daemon/lightning-cli: $(DAEMON_CLI_OBJS) $(DAEMON_LIB_OBJS) $(DAEMON_JSMN_OBJS) $(CORE_OBJS) $(BITCOIN_OBJS) $(LIBBASE58_OBJS) $(WIRE_OBJS) $(CCAN_OBJS) libsecp256k1.a libsodium.a
daemon-clean: daemon-clean:
$(RM) $(DAEMON_OBJS) $(DAEMON_LIB_OBJS) $(DAEMON_CLI_OBJS) $(DAEMON_JSMN_OBJS) $(DAEMON_GEN_HEADERS) $(RM) $(DAEMON_LIB_OBJS) $(DAEMON_CLI_OBJS) $(DAEMON_JSMN_OBJS) $(DAEMON_GEN_HEADERS)
daemon-maintainer-clean: daemon-maintainer-clean:
include daemon/test/Makefile

1
daemon/chaintopology.c

@ -5,7 +5,6 @@
#include "jsonrpc.h" #include "jsonrpc.h"
#include "lightningd.h" #include "lightningd.h"
#include "log.h" #include "log.h"
#include "peer.h"
#include "timeout.h" #include "timeout.h"
#include "utils.h" #include "utils.h"
#include "watch.h" #include "watch.h"

359
daemon/channel.c

@ -1,359 +0,0 @@
#include "channel.h"
#include "htlc.h"
#include "remove_dust.h"
#include "type_to_string.h"
#include <assert.h>
#include <ccan/array_size/array_size.h>
#include <ccan/mem/mem.h>
#include <ccan/structeq/structeq.h>
#include <ccan/tal/str/str.h>
#include <inttypes.h>
#include <string.h>
uint64_t fee_by_feerate(size_t txsize, uint64_t fee_rate)
{
/* FIXME-OLD #2:
*
* The fee for a transaction MUST be calculated by multiplying this
* bytecount by the fee rate, dividing by 1000 and truncating
* (rounding down) the result to an even number of satoshis.
*/
return txsize * fee_rate / 2000 * 2;
}
/* FIXME-OLD #2:
*
* A node MUST use the formula 338 + 32 bytes for every non-dust HTLC
* as the bytecount for calculating commitment transaction fees. Note
* that the fee requirement is unchanged, even if the elimination of
* dust HTLC outputs has caused a non-zero fee already.
*/
static size_t tx_bytes(size_t num_nondust_htlcs)
{
return 338 + 32 * num_nondust_htlcs;
}
static uint64_t calculate_fee_msat(size_t num_nondust_htlcs,
uint64_t fee_rate)
{
/* milli-satoshis */
return fee_by_feerate(tx_bytes(num_nondust_htlcs), fee_rate) * 1000;
}
/* Pay this much fee, if possible. Return amount unpaid. */
static uint64_t pay_fee(struct channel_oneside *side, uint64_t fee_msat)
{
if (side->pay_msat >= fee_msat) {
side->pay_msat -= fee_msat;
side->fee_msat += fee_msat;
return 0;
} else {
uint64_t remainder = fee_msat - side->pay_msat;
side->fee_msat += side->pay_msat;
side->pay_msat = 0;
return remainder;
}
}
/* Charge the fee as per FIXME-OLD #2 */
static void recalculate_fees(struct channel_oneside *a,
struct channel_oneside *b,
uint64_t fee_msat)
{
uint64_t remainder;
/* Fold in fees, to recalcuate again below. */
a->pay_msat += a->fee_msat;
b->pay_msat += b->fee_msat;
a->fee_msat = b->fee_msat = 0;
/* FIXME-OLD #2:
*
* 1. If each nodes can afford half the fee from their
* to-`final_key` output, reduce the two to-`final_key`
* outputs accordingly.
*
* 2. Otherwise, reduce the to-`final_key` output of one node
* which cannot afford the fee to zero (resulting in that
* entire output paying fees). If the remaining
* to-`final_key` output is greater than the fee remaining,
* reduce it accordingly, otherwise reduce it to zero to
* pay as much fee as possible.
*/
remainder = pay_fee(a, fee_msat / 2) + pay_fee(b, fee_msat / 2);
/* If there's anything left, the other side tries to pay for it. */
remainder = pay_fee(a, remainder);
pay_fee(b, remainder);
}
/* a transfers htlc_msat to a HTLC (gains it, if -ve) */
static bool change_funding(uint64_t anchor_satoshis,
uint64_t fee_rate,
int64_t htlc_msat,
struct channel_oneside *a,
struct channel_oneside *b,
size_t num_nondust_htlcs,
bool must_afford_fee)
{
uint64_t fee_msat;
uint64_t htlcs_total;
htlcs_total = anchor_satoshis * 1000
- (a->pay_msat + a->fee_msat + b->pay_msat + b->fee_msat);
fee_msat = calculate_fee_msat(num_nondust_htlcs, fee_rate);
/* If A is paying, can it afford it? */
if (htlc_msat >= 0) {
uint64_t cost = htlc_msat;
if (must_afford_fee)
cost += fee_msat / 2;
if (cost > a->pay_msat + a->fee_msat)
return false;
}
/* OK, now adjust funds for A, then recalculate fees. */
a->pay_msat -= htlc_msat;
recalculate_fees(a, b, fee_msat);
htlcs_total += htlc_msat;
assert(htlcs_total == anchor_satoshis * 1000
- (a->pay_msat + a->fee_msat + b->pay_msat + b->fee_msat));
return true;
}
bool anchor_too_large(uint64_t anchor_satoshis)
{
/* Anchor must fit in 32 bit. */
return anchor_satoshis >= (1ULL << 32) / 1000;
}
struct channel_state *initial_cstate(const tal_t *ctx,
uint64_t anchor_satoshis,
uint64_t fee_rate,
enum side funding)
{
uint64_t fee_msat;
struct channel_state *cstate = talz(ctx, struct channel_state);
struct channel_oneside *funder, *fundee;
cstate->fee_rate = fee_rate;
cstate->anchor = anchor_satoshis;
cstate->num_nondust = 0;
/* Anchor must fit in 32 bit. */
assert(!anchor_too_large(anchor_satoshis));
fee_msat = calculate_fee_msat(0, fee_rate);
if (fee_msat > anchor_satoshis * 1000)
return tal_free(cstate);
funder = &cstate->side[funding];
fundee = &cstate->side[!funding];
/* Neither side has HTLCs. */
funder->num_htlcs = fundee->num_htlcs = 0;
/* Initially, all goes back to funder. */
funder->pay_msat = anchor_satoshis * 1000 - fee_msat;
funder->fee_msat = fee_msat;
/* Make sure it checks out. */
assert(change_funding(anchor_satoshis, fee_rate, 0, funder, fundee, 0, false));
assert(funder->fee_msat == fee_msat);
assert(fundee->fee_msat == 0);
return cstate;
}
/* FIXME: Write exact variant! */
uint64_t approx_max_feerate(const struct channel_state *cstate,
enum side side)
{
uint64_t max_funds;
max_funds = cstate->side[side].pay_msat + cstate->side[side].fee_msat;
return max_funds / tx_bytes(cstate->num_nondust);
}
bool can_afford_feerate(const struct channel_state *cstate, uint64_t fee_rate,
enum side side)
{
u64 fee_msat = calculate_fee_msat(cstate->num_nondust, fee_rate);
return cstate->side[side].pay_msat + cstate->side[side].fee_msat
>= fee_msat;
}
void adjust_fee(struct channel_state *cstate, uint64_t fee_rate)
{
uint64_t fee_msat;
fee_msat = calculate_fee_msat(cstate->num_nondust, fee_rate);
recalculate_fees(&cstate->side[LOCAL], &cstate->side[REMOTE], fee_msat);
}
bool force_fee(struct channel_state *cstate, uint64_t fee)
{
/* Beware overflow! */
if (fee > 0xFFFFFFFFFFFFFFFFULL / 1000)
return false;
recalculate_fees(&cstate->side[LOCAL], &cstate->side[REMOTE], fee * 1000);
return cstate->side[LOCAL].fee_msat + cstate->side[REMOTE].fee_msat == fee * 1000;
}
/* Add a HTLC to @creator if it can afford it. */
bool cstate_add_htlc(struct channel_state *cstate, const struct htlc *htlc,
bool must_afford_fee)
{
size_t nondust;
struct channel_oneside *creator, *recipient;
creator = &cstate->side[htlc_owner(htlc)];
recipient = &cstate->side[!htlc_owner(htlc)];
/* Remember to count the new one in total txsize if not dust! */
nondust = cstate->num_nondust;
if (!is_dust(htlc->msatoshi / 1000))
nondust++;
if (!change_funding(cstate->anchor, cstate->fee_rate,
htlc->msatoshi, creator, recipient, nondust,
must_afford_fee))
return false;
cstate->num_nondust = nondust;
creator->num_htlcs++;
return true;
}
/* Remove htlc from creator, credit it to beneficiary. */
static void remove_htlc(struct channel_state *cstate,
enum side creator,
enum side beneficiary,
const struct htlc *htlc)
{
size_t nondust;
/* Remember to remove this one in total txsize if not dust! */
nondust = cstate->num_nondust;
if (!is_dust(htlc->msatoshi / 1000)) {
assert(nondust > 0);
nondust--;
}
/* Can't fail since msatoshi is positive. */
if (!change_funding(cstate->anchor, cstate->fee_rate,
-(int64_t)htlc->msatoshi,
&cstate->side[beneficiary],
&cstate->side[!beneficiary], nondust, false))
abort();
/* Actually remove the HTLC. */
assert(cstate->side[creator].num_htlcs > 0);
cstate->side[creator].num_htlcs--;
cstate->num_nondust = nondust;
}
void cstate_fail_htlc(struct channel_state *cstate, const struct htlc *htlc)
{
remove_htlc(cstate, htlc_owner(htlc), htlc_owner(htlc), htlc);
}
void cstate_fulfill_htlc(struct channel_state *cstate, const struct htlc *htlc)
{
remove_htlc(cstate, htlc_owner(htlc), !htlc_owner(htlc), htlc);
}
struct channel_state *copy_cstate(const tal_t *ctx,
const struct channel_state *cstate)
{
return tal_dup(ctx, struct channel_state, cstate);
}
void force_add_htlc(struct channel_state *cstate, const struct htlc *htlc)
{
struct channel_oneside *creator;
creator = &cstate->side[htlc_owner(htlc)];
creator->num_htlcs++;
creator->pay_msat -= htlc->msatoshi;
/* Remember to count the new one in total txsize if not dust! */
if (!is_dust(htlc->msatoshi / 1000))
cstate->num_nondust++;
}
static void force_remove_htlc(struct channel_state *cstate,
enum side beneficiary,
const struct htlc *htlc)
{
cstate->side[beneficiary].pay_msat += htlc->msatoshi;
cstate->side[htlc_owner(htlc)].num_htlcs--;
if (!is_dust(htlc->msatoshi / 1000))
cstate->num_nondust--;
}
void force_fail_htlc(struct channel_state *cstate, const struct htlc *htlc)
{
force_remove_htlc(cstate, htlc_owner(htlc), htlc);
}
void force_fulfill_htlc(struct channel_state *cstate, const struct htlc *htlc)
{
force_remove_htlc(cstate, !htlc_owner(htlc), htlc);
}
bool balance_after_force(struct channel_state *cstate)
{
/* We should not spend more than anchor */
if (cstate->side[LOCAL].pay_msat + cstate->side[REMOTE].pay_msat
> cstate->anchor * 1000)
return false;
/* Check for wrap. */
if (cstate->side[LOCAL].pay_msat > cstate->anchor * 1000)
return false;
if (cstate->side[REMOTE].pay_msat > cstate->anchor * 1000)
return false;
if (cstate->num_nondust
> cstate->side[LOCAL].num_htlcs + cstate->side[REMOTE].num_htlcs)
return false;
/* Recalc fees. */
adjust_fee(cstate, cstate->fee_rate);
return true;
}
static char *fmt_channel_oneside(const tal_t *ctx,
const struct channel_oneside *co)
{
return tal_fmt(ctx, "{ pay_msat=%u"
" fee_msat=%u"
" num_htlcs=%u }",
co->pay_msat,
co->fee_msat,
co->num_htlcs);
}
static char *fmt_channel_state(const tal_t *ctx,
const struct channel_state *cs)
{
return tal_fmt(ctx, "{ anchor=%"PRIu64
" fee_rate=%"PRIu64
" num_nondust=%u"
" ours=%s"
" theirs=%s }",
cs->anchor,
cs->fee_rate,
cs->num_nondust,
fmt_channel_oneside(ctx, &cs->side[LOCAL]),
fmt_channel_oneside(ctx, &cs->side[REMOTE]));
}
REGISTER_TYPE_TO_STRING(channel_oneside, fmt_channel_oneside);
REGISTER_TYPE_TO_STRING(channel_state, fmt_channel_state);

140
daemon/channel.h

@ -1,140 +0,0 @@
#ifndef LIGHTNING_DAEMON_CHANNEL_H
#define LIGHTNING_DAEMON_CHANNEL_H
#include "config.h"
#include "bitcoin/locktime.h"
#include "daemon/htlc.h"
#include <assert.h>
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/tal/tal.h>
#include <stdbool.h>
struct channel_oneside {
/* Payment and fee is in millisatoshi. */
uint32_t pay_msat, fee_msat;
/* Number of HTLCs (required for limiting total number) */
unsigned int num_htlcs;
};
struct channel_state {
/* Satoshis paid by anchor. */
uint64_t anchor;
/* Satoshis per 1000 bytes. */
uint64_t fee_rate;
/* Number of non-dust htlcs (to calculate txsize) */
unsigned int num_nondust;
struct channel_oneside side[2];
};
/**
* initial_cstate: Given initial fees and funding anchor, what is initial state?
* @ctx: tal context to allocate return value from.
* @anchor_satoshis: The anchor amount.
* @fee_rate: amount to pay in fees per kb (in satoshi).
* @dir: which side paid for the anchor.
*
* Returns state, or NULL if malformed.
*/
struct channel_state *initial_cstate(const tal_t *ctx,
uint64_t anchor_satoshis,
uint64_t fee_rate,
enum side side);
/**
* copy_cstate: Make a deep copy of channel_state
* @ctx: tal context to allocate return value from.
* @cstate: state to copy.
*/
struct channel_state *copy_cstate(const tal_t *ctx,
const struct channel_state *cstate);
/**
* cstate_add_htlc: append an HTLC to cstate if it can afford it
* @cstate: The channel state
* @htlc: the htlc pointer.
* @must_afford_fee: true if payer must meet fee.
*
* If that direction can't afford the HTLC this will return false and
* leave @cstate unchanged. If @must_afford_fee is true, and the
* direction can't afford its half of the fees, it will also return
* false and leave @cstate unchanged. Otherwise, pay_msat and fee_msat
* are adjusted accordingly; true is returned.
*/
bool cstate_add_htlc(struct channel_state *cstate, const struct htlc *htlc,
bool must_afford_fee);
/**
* cstate_fail_htlc: remove an HTLC, funds to the side which offered it.
* @cstate: The channel state
* @htlc: the htlc to remove.
*
* This will remove the @index'th entry in cstate->side[dir].htlcs[], and credit
* the value of the HTLC (back) to cstate->side[dir].
*/
void cstate_fail_htlc(struct channel_state *cstate, const struct htlc *htlc);
/**
* cstate_fulfill_htlc: remove an HTLC, funds to side which accepted it.
* @cstate: The channel state
* @htlc: the htlc to remove
*
* This will remove the @index'th entry in cstate->side[dir].htlcs[], and credit
* the value of the HTLC to cstate->side[!dir].
*/
void cstate_fulfill_htlc(struct channel_state *cstate, const struct htlc *htlc);
/**
* approx_max_feerate: what's the most side could raise fee rate to?
* @cstate: The channel state
* @side: LOCAL or REMOTE
*
* This is not exact! To check if their offer is valid, use can_afford_feerate.
*/
uint64_t approx_max_feerate(const struct channel_state *cstate,
enum side side);
/**
* can_afford_feerate: could this side pay for the fee if changed to fee_rate?
* @cstate: The channel state
* @fee_rate: the new fee rate proposed
* @side: LOCAL or REMOTE
*/
bool can_afford_feerate(const struct channel_state *cstate, uint64_t fee_rate,
enum side side);
/**
* adjust_fee: Change fee rate.
* @cstate: The channel state
* @fee_rate: fee in satoshi per 1000 bytes.
*/
void adjust_fee(struct channel_state *cstate, uint64_t fee_rate);
/**
* force_fee: Change fee to a specific value.
* @cstate: The channel state
* @fee: fee in satoshi.
*
* This is used for the close transaction, which specifies an exact fee.
* If the fee cannot be paid in full, this return false (but cstate will
* still be altered).
*/
bool force_fee(struct channel_state *cstate, uint64_t fee);
/**
* fee_for_feerate: calculate the fee (in satoshi) for a given fee_rate.
* @txsize: transaction size in bytes.
* @fee_rate: satoshi per 1000 bytes.
*/
uint64_t fee_by_feerate(size_t txsize, uint64_t fee_rate);
/**
* anchor_too_large: does anchor amount fit in 32-bits of millisatoshi.
* @anchor_satoshis: amount in satoshis
*/
bool anchor_too_large(uint64_t anchor_satoshis);
/* Routines to db to force HTLC changes out-of-order which may wrap. */
void force_add_htlc(struct channel_state *cstate, const struct htlc *htlc);
void force_fail_htlc(struct channel_state *cstate, const struct htlc *htlc);
void force_fulfill_htlc(struct channel_state *cstate, const struct htlc *htlc);
bool balance_after_force(struct channel_state *cstate);
#endif /* LIGHTNING_DAEMON_CHANNEL_H */

225
daemon/commit_tx.c

@ -1,225 +0,0 @@
#include "bitcoin/locktime.h"
#include "bitcoin/pubkey.h"
#include "bitcoin/script.h"
#include "bitcoin/shadouble.h"
#include "bitcoin/tx.h"
#include "channel.h"
#include "commit_tx.h"
#include "htlc.h"
#include "lightningd.h"
#include "log.h"
#include "overflows.h"
#include "peer.h"
#include "peer_internal.h"
#include "permute_tx.h"
#include "remove_dust.h"
#include "utils.h"
#include <assert.h>
#include <inttypes.h>
u8 *wscript_for_htlc(const tal_t *ctx,
const struct peer *peer,
const struct htlc *h,
const struct sha256 *rhash,
enum side side)
{
const struct peer_visible_state *this_side, *other_side;
u8 *(*fn)(const tal_t *,
const struct pubkey *, const struct pubkey *,
const struct abs_locktime *, const struct rel_locktime *,
const struct sha256 *, const struct sha256 *);
/* scripts are different for htlcs offered vs accepted */
if (side == htlc_owner(h))
fn = bitcoin_redeem_htlc_send;
else
fn = bitcoin_redeem_htlc_recv;
if (side == LOCAL) {
this_side = &peer->local;
other_side = &peer->remote;
} else {
this_side = &peer->remote;
other_side = &peer->local;
}
return fn(ctx,
&this_side->finalkey, &other_side->finalkey,
&h->expiry, &this_side->locktime, rhash, &h->rhash);
}
static size_t count_htlcs(const struct htlc_map *htlcs, int flag)
{
struct htlc_map_iter it;
struct htlc *h;
size_t n = 0;
for (h = htlc_map_first(htlcs, &it); h; h = htlc_map_next(htlcs, &it)) {
if (htlc_has(h, flag))
n++;
}
return n;
}
u8 *commit_output_to_us(const tal_t *ctx,
const struct peer *peer,
const struct sha256 *rhash,
enum side side,
u8 **wscript)
{
u8 *tmp;
if (!wscript)
wscript = &tmp;
/* Our output to ourself is encumbered by delay. */
if (side == LOCAL) {
*wscript = bitcoin_redeem_secret_or_delay(ctx,
&peer->local.finalkey,
&peer->remote.locktime,
&peer->remote.finalkey,
rhash);
return scriptpubkey_p2wsh(ctx, *wscript);
} else {
/* Their output to us is a simple p2wpkh */
*wscript = NULL;
return scriptpubkey_p2wpkh(ctx, &peer->local.finalkey);
}
}
u8 *commit_output_to_them(const tal_t *ctx,
const struct peer *peer,
const struct sha256 *rhash,
enum side side,
u8 **wscript)
{
u8 *tmp;
if (!wscript)
wscript = &tmp;
/* Their output to themselves is encumbered by delay. */
if (side == REMOTE) {
*wscript = bitcoin_redeem_secret_or_delay(ctx,
&peer->remote.finalkey,
&peer->local.locktime,
&peer->local.finalkey,
rhash);
return scriptpubkey_p2wsh(ctx, *wscript);
} else {
/* Our output to them is a simple p2wpkh */
*wscript = NULL;
return scriptpubkey_p2wpkh(ctx, &peer->remote.finalkey);
}
}
/* Takes ownership of script. */
static bool add_output(struct bitcoin_tx *tx, u8 *script, u64 amount,
size_t *output_count,
u64 *total)
{
assert(*output_count < tal_count(tx->output));
if (is_dust(amount))
return false;
tx->output[*output_count].script = tal_steal(tx, script);
tx->output[*output_count].amount = amount;
(*output_count)++;
(*total) += amount;
return true;
}
struct bitcoin_tx *create_commit_tx(const tal_t *ctx,
struct peer *peer,
const struct sha256 *rhash,
const struct channel_state *cstate,
enum side side,
bool *otherside_only)
{
const tal_t *tmpctx = tal_tmpctx(ctx);
struct bitcoin_tx *tx;
uint64_t total = 0;
struct htlc_map_iter it;
struct htlc *h;
size_t output_count;
bool pays_to[2];
int committed_flag = HTLC_FLAG(side,HTLC_F_COMMITTED);
/* Now create commitment tx: one input, two outputs (plus htlcs) */
tx = bitcoin_tx(ctx, 1, 2 + count_htlcs(&peer->htlcs, committed_flag));
log_debug(peer->log, "Creating commitment tx:");
log_add_struct(peer->log, " rhash = %s", struct sha256, rhash);
log_add_struct(peer->log, " My finalkey = %s", struct pubkey,
&peer->local.finalkey);
log_add_struct(peer->log, " Their finalkey = %s", struct pubkey,
&peer->remote.finalkey);
log_add_struct(peer->log, " My locktime = %s", struct rel_locktime,
&peer->local.locktime);
log_add_struct(peer->log, " Their locktime = %s", struct rel_locktime,
&peer->remote.locktime);
/* Our input spends the anchor tx output. */
tx->input[0].txid = peer->anchor.txid;
tx->input[0].index = peer->anchor.index;
tx->input[0].amount = tal_dup(tx->input, u64, &peer->anchor.satoshis);
output_count = 0;
pays_to[LOCAL] = add_output(tx, commit_output_to_us(tmpctx, peer, rhash,
side, NULL),
cstate->side[LOCAL].pay_msat / 1000,
&output_count,
&total);
if (pays_to[LOCAL])
log_debug(peer->log, "Pays %u to local: %s",
cstate->side[LOCAL].pay_msat / 1000,
tal_hex(tmpctx, tx->output[output_count-1].script));
else
log_debug(peer->log, "DOES NOT pay %u to local",
cstate->side[LOCAL].pay_msat / 1000);
pays_to[REMOTE] = add_output(tx, commit_output_to_them(tmpctx, peer,
rhash, side,
NULL),
cstate->side[REMOTE].pay_msat / 1000,
&output_count,
&total);
if (pays_to[REMOTE])
log_debug(peer->log, "Pays %u to remote: %s",
cstate->side[REMOTE].pay_msat / 1000,
tal_hex(tmpctx, tx->output[output_count-1].script));
else
log_debug(peer->log, "DOES NOT pay %u to remote",
cstate->side[REMOTE].pay_msat / 1000);
/* If their tx doesn't pay to them, or our tx doesn't pay to us... */
*otherside_only = !pays_to[side];
/* First two outputs done, now for the HTLCs. */
for (h = htlc_map_first(&peer->htlcs, &it);
h;
h = htlc_map_next(&peer->htlcs, &it)) {
const u8 *wscript;
if (!htlc_has(h, committed_flag))
continue;
wscript = wscript_for_htlc(tmpctx, peer, h, rhash, side);
/* If we pay any HTLC, it's txout is not just to other side. */
if (add_output(tx, scriptpubkey_p2wsh(tmpctx, wscript),
h->msatoshi / 1000, &output_count, &total)) {
*otherside_only = false;
log_debug(peer->log, "Pays %"PRIu64" to htlc %"PRIu64,
h->msatoshi / 1000, h->id);
log_add_struct(peer->log, " expiry %s",
struct abs_locktime, &h->expiry);
log_add_struct(peer->log, " rhash %s", struct sha256,
&h->rhash);
log_debug(peer->log, "Script: %s",
tal_hex(tmpctx, wscript));
} else
log_debug(peer->log, "DOES NOT pay %"PRIu64" to htlc %"PRIu64,
h->msatoshi / 1000, h->id);
}
assert(total <= peer->anchor.satoshis);
tal_resize(&tx->output, output_count);
permute_outputs(tx->output, tal_count(tx->output), NULL);
tal_free(tmpctx);
return tx;
}

40
daemon/commit_tx.h

@ -1,40 +0,0 @@
#ifndef LIGHTNING_COMMIT_TX_H
#define LIGHTNING_COMMIT_TX_H
#include "config.h"
#include "htlc.h"
#include <ccan/tal/tal.h>
struct channel_state;
struct sha256;
struct pubkey;
struct peer;
u8 *wscript_for_htlc(const tal_t *ctx,
const struct peer *peer,
const struct htlc *h,
const struct sha256 *rhash,
enum side side);
/* Returns scriptpubkey: *wscript is NULL if it's a direct p2wpkh. */
u8 *commit_output_to_us(const tal_t *ctx,
const struct peer *peer,
const struct sha256 *rhash,
enum side side,
u8 **wscript);
/* Returns scriptpubkey: *wscript is NULL if it's a direct p2wpkh. */
u8 *commit_output_to_them(const tal_t *ctx,
const struct peer *peer,
const struct sha256 *rhash,
enum side side,
u8 **wscript);
/* Create commitment tx to spend the anchor tx output; doesn't fill in
* input scriptsig. */
struct bitcoin_tx *create_commit_tx(const tal_t *ctx,
struct peer *peer,
const struct sha256 *rhash,
const struct channel_state *cstate,
enum side side,
bool *otherside_only);
#endif

656
daemon/cryptopkt.c

@ -1,656 +0,0 @@
#include "bitcoin/shadouble.h"
#include "bitcoin/signature.h"
#include "cryptopkt.h"
#include "lightning.pb-c.h"
#include "lightningd.h"
#include "log.h"
#include "names.h"
#include "peer.h"
#include "peer_internal.h"
#include "protobuf_convert.h"
#include "secrets.h"
#include "utils.h"
#include <ccan/build_assert/build_assert.h>
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/endian/endian.h>
#include <ccan/mem/mem.h>
#include <ccan/short_types/short_types.h>
#include <ccan/structeq/structeq.h>
#include <inttypes.h>
#include <secp256k1.h>
#include <secp256k1_ecdh.h>
#include <sodium/crypto_aead_chacha20poly1305.h>
#include <sodium/randombytes.h>
#define MAX_PKT_LEN (1024 * 1024)
/* FIXME-OLD#1:
`length` is a 4-byte little-endian field indicating the size of the unencrypted body.
*/
struct crypto_pkt {
le32 length;
u8 auth_tag[crypto_aead_chacha20poly1305_ABYTES];
/* ... contents... */
u8 data[];
};
/* Temporary structure for negotiation */
struct key_negotiate {
struct lightningd_state *dstate;
/* Our session secret key. */
u8 seckey[32];
/* Our pubkey, their pubkey. */
le32 keylen;
u8 our_sessionpubkey[33], their_sessionpubkey[33];
/* After DH key exchange, we create io_data to check auth. */
struct io_data *iod;
/* Logging structure we're using. */
struct log *log;
/* Did we expect a particular ID? */
const struct pubkey *expected_id;
/* Callback once it's all done. */
struct io_plan *(*cb)(struct io_conn *conn,
struct lightningd_state *dstate,
struct io_data *iod,
struct log *log,
const struct pubkey *id,
void *arg);
void *arg;
};
struct enckey {
struct sha256 k;
};
/* FIXME-OLD #1:
* * sending-key: SHA256(shared-secret || sending-node-session-pubkey)
* * receiving-key: SHA256(shared-secret || receiving-node-session-pubkey)
*/
static struct enckey enckey_from_secret(const unsigned char secret[32],
const unsigned char serial_pubkey[33])
{
struct sha256_ctx ctx;
struct enckey enckey;
sha256_init(&ctx);
sha256_update(&ctx, memcheck(secret, 32), 32);
sha256_update(&ctx, memcheck(serial_pubkey, 33), 33);
sha256_done(&ctx, &enckey.k);
return enckey;
}
struct dir_state {
u64 nonce;
struct enckey enckey;
/* Current packet (encrypted). */
struct crypto_pkt *cpkt;
size_t pkt_len;
};
static void setup_crypto(struct dir_state *dir,
u8 shared_secret[32], u8 serial_pubkey[33])
{
/* FIXME-OLD #1: Nonces...MUST begin at 0 */
dir->nonce = 0;
dir->enckey = enckey_from_secret(shared_secret, serial_pubkey);
dir->cpkt = NULL;
}
struct io_data {
/* Stuff we need to keep around to talk to peer. */
struct dir_state in, out;
/* Callback once packet decrypted. */
struct io_plan *(*cb)(struct io_conn *, struct peer *);
/* Once peer is assigned, this is set. */
struct peer *peer;
/* Length we're currently reading. */
struct crypto_pkt hdr_in;
};
static void *proto_tal_alloc(void *allocator_data, size_t size)
{
return tal_arr(allocator_data, char, size);
}
static void proto_tal_free(void *allocator_data, void *pointer)
{
tal_free(pointer);
}
static void le64_nonce(unsigned char *npub, u64 nonce)
{
/* FIXME-OLD #1: Nonces are 64-bit little-endian numbers */
le64 le_nonce = cpu_to_le64(nonce);
memcpy(npub, &le_nonce, sizeof(le_nonce));
BUILD_ASSERT(crypto_aead_chacha20poly1305_NPUBBYTES == sizeof(le_nonce));
}
/* Encrypts data..data + len - 1 inclusive into data..data + len - 1 and
* then writes the authentication tag at data+len.
*
* This increments nonce every time.
*/
static void encrypt_in_place(void *data, size_t len,
u64 *nonce, const struct enckey *enckey)
{
int ret;
unsigned long long clen;
unsigned char npub[crypto_aead_chacha20poly1305_NPUBBYTES];
le64_nonce(npub, *nonce);
ret = crypto_aead_chacha20poly1305_encrypt(data, &clen,
memcheck(data, len), len,
NULL, 0, NULL,
npub, enckey->k.u.u8);
assert(ret == 0);
assert(clen == len + crypto_aead_chacha20poly1305_ABYTES);
(*nonce)++;
}
/* Checks authentication tag at data+len, then
* decrypts data..data + len - 1 inclusive into data..data + len - 1.
*
* This increments nonce every time.
*/
static bool decrypt_in_place(void *data, size_t len,
u64 *nonce, const struct enckey *enckey)
{
int ret;
unsigned long long mlen;
unsigned char npub[crypto_aead_chacha20poly1305_NPUBBYTES];
le64_nonce(npub, *nonce);
mlen = len + crypto_aead_chacha20poly1305_ABYTES;
ret = crypto_aead_chacha20poly1305_decrypt(data, &mlen, NULL,
memcheck(data, mlen), mlen,
NULL, 0,
npub, enckey->k.u.u8);
if (ret == 0) {
assert(mlen == len);
(*nonce)++;
return true;
}
return false;
}
static Pkt *decrypt_body(const tal_t *ctx, struct io_data *iod, struct log *log)
{
struct ProtobufCAllocator prototal;
Pkt *ret;
size_t data_len = le32_to_cpu(iod->hdr_in.length);
if (!decrypt_in_place(iod->in.cpkt->data, data_len,
&iod->in.nonce, &iod->in.enckey)) {
/* Free encrypted packet. */
iod->in.cpkt = tal_free(iod->in.cpkt);
log_unusual(log, "Body decryption failed");
return NULL;
}
/* De-protobuf it. */
prototal.alloc = proto_tal_alloc;
prototal.free = proto_tal_free;
prototal.allocator_data = tal(ctx, char);
ret = pkt__unpack(&prototal, data_len, iod->in.cpkt->data);
if (!ret) {
log_unusual(log, "Packet failed to unpack!");
tal_free(prototal.allocator_data);
} else {
/* Make sure packet owns contents */
tal_steal(ctx, ret);
tal_steal(ret, prototal.allocator_data);
log_debug(log, "Received packet LEN=%zu, type=%s",
data_len,
ret->pkt_case == PKT__PKT_AUTH ? "PKT_AUTH"
: pkt_name(ret->pkt_case));
}
/* Free encrypted packet. */
iod->in.cpkt = tal_free(iod->in.cpkt);
return ret;
}
static struct crypto_pkt *encrypt_pkt(struct io_data *iod, const Pkt *pkt,
size_t *totlen)
{
struct crypto_pkt *cpkt;
size_t len;
len = pkt__get_packed_size(pkt);
*totlen = sizeof(*cpkt) + len + crypto_aead_chacha20poly1305_ABYTES;
cpkt = (struct crypto_pkt *)tal_arr(iod, char, *totlen);
cpkt->length = cpu_to_le32(len);
/* Encrypt header. */
encrypt_in_place(cpkt, sizeof(cpkt->length),
&iod->out.nonce, &iod->out.enckey);
/* Encrypt body. */
pkt__pack(pkt, cpkt->data);
encrypt_in_place(cpkt->data, len, &iod->out.nonce, &iod->out.enckey);
return cpkt;
}
static struct io_plan *recv_body(struct io_conn *conn, struct peer *peer)
{
struct io_data *iod = peer->io_data;
assert(!peer->inpkt);
/* We have full packet. */
peer->inpkt = decrypt_body(iod, iod, peer->log);
if (!peer->inpkt)
return io_close(conn);
return iod->cb(conn, peer);
}
static bool decrypt_header(struct log *log, struct io_data *iod,
size_t *body_len)
{
/* We have length: Check it. */
if (!decrypt_in_place(&iod->hdr_in.length, sizeof(iod->hdr_in.length),
&iod->in.nonce, &iod->in.enckey)) {
log_unusual(log, "Header decryption failed");
return false;
}
log_debug(log, "Decrypted header len %u",
le32_to_cpu(iod->hdr_in.length));
/* FIXME-OLD #1: `length` MUST NOT exceed 1MB (1048576 bytes). */
if (le32_to_cpu(iod->hdr_in.length) > MAX_PKT_LEN) {
log_unusual(log,
"Packet overlength: %"PRIu64,
le64_to_cpu(iod->hdr_in.length));
return false;
}
/* Allocate room for body, copy header. */
*body_len = le32_to_cpu(iod->hdr_in.length)
+ crypto_aead_chacha20poly1305_ABYTES;
iod->in.cpkt = (struct crypto_pkt *)
tal_arr(iod, char, sizeof(iod->hdr_in) + *body_len);
*iod->in.cpkt = iod->hdr_in;
return true;
}
static struct io_plan *recv_header(struct io_conn *conn, struct peer *peer)
{
struct io_data *iod = peer->io_data;
size_t body_len;
if (!decrypt_header(peer->log, iod, &body_len))
return io_close(conn);
return io_read(conn, iod->in.cpkt->data, body_len, recv_body, peer);
}
struct io_plan *peer_read_packet(struct io_conn *conn,
struct peer *peer,
struct io_plan *(*cb)(struct io_conn *,
struct peer *))
{
struct io_data *iod = peer->io_data;
iod->cb = cb;
return io_read(conn, &iod->hdr_in, sizeof(iod->hdr_in),
recv_header, peer);
}
/* Caller must free data! */
struct io_plan *peer_write_packet(struct io_conn *conn,
struct peer *peer,
const Pkt *pkt,
struct io_plan *(*next)(struct io_conn *,
struct peer *))
{
struct io_data *iod = peer->io_data;
size_t totlen;
/* We free previous packet here, rather than doing indirection
* via io_write */
tal_free(iod->out.cpkt);
iod->out.cpkt = encrypt_pkt(iod, pkt, &totlen);
/* Free unencrypted packet. */
tal_free(pkt);
return io_write(conn, iod->out.cpkt, totlen, next, peer);
}
static void *pkt_unwrap(Pkt *inpkt, struct log *log, Pkt__PktCase which)
{
size_t i;
const ProtobufCMessage *base;
if (inpkt->pkt_case != which) {
log_unusual(log, "Expected %u, got %u",
which, inpkt->pkt_case);
return NULL;
}
/* It's a union, and each member starts with base. Pick one */
base = &inpkt->error->base;
/* Look for unknown fields. Remember, "It's OK to be odd!" */
for (i = 0; i < base->n_unknown_fields; i++) {
log_debug(log, "Unknown field in %u: %u",
which, base->unknown_fields[i].tag);
/* Odd is OK */
if (base->unknown_fields[i].tag & 1)
continue;
log_unusual(log, "Unknown field %u in %u",
base->unknown_fields[i].tag, which);
return NULL;
}
return inpkt->error;
}
static bool check_proof(struct key_negotiate *neg, struct log *log,
Pkt *inpkt,
const struct pubkey *expected_id,
struct pubkey *id)
{
struct sha256_double sha;
secp256k1_ecdsa_signature sig;
Authenticate *auth;
auth = pkt_unwrap(inpkt, log, PKT__PKT_AUTH);
if (!auth)
return false;
/* FIXME-OLD #1:
*
* The receiving node MUST check that:
*
* 1. `node_id` is the expected value for the sending node.
*/
if (!proto_to_pubkey(auth->node_id, id)) {
log_unusual(log, "Invalid auth id");
return false;
}
if (expected_id && !structeq(id, expected_id)) {
log_unusual(log, "Incorrect auth id");
return false;
}
/* FIXME-OLD #1:
*
* 2. `session_sig` is a valid secp256k1 ECDSA signature encoded as
* a 32-byte big endian R value, followed by a 32-byte big
* endian S value.
*/
if (!proto_to_signature(auth->session_sig, &sig)) {
log_unusual(log, "Invalid auth signature");
return false;
}
/* FIXME-OLD #1:
*
* 3. `session_sig` is the signature of the SHA256 of SHA256 of the
* its own sessionpubkey, using the secret key corresponding to
* the sender's `node_id`.
*/
sha256_double(&sha, neg->our_sessionpubkey,
sizeof(neg->our_sessionpubkey));
if (!check_signed_hash(&sha, &sig, id)) {
log_unusual(log, "Bad auth signature");
return false;
}
return true;
}
static struct io_plan *recv_body_negotiate(struct io_conn *conn,
struct key_negotiate *neg)
{
struct io_data *iod = neg->iod;
struct io_plan *plan;
Pkt *pkt;
struct pubkey id;
/* We have full packet. */
pkt = decrypt_body(neg, iod, neg->log);
if (!pkt)
return io_close(conn);
if (!check_proof(neg, neg->log, pkt, neg->expected_id, &id))
return io_close(conn);
/* Steal so that the callback may not accidentally free it for us */
tal_steal(NULL, neg);
plan = neg->cb(conn, neg->dstate, neg->iod, neg->log, &id, neg->arg);
tal_free(neg);
return plan;
}
static struct io_plan *recv_header_negotiate(struct io_conn *conn,
struct key_negotiate *neg)
{
size_t body_len;
struct io_data *iod = neg->iod;
if (!decrypt_header(neg->log, iod, &body_len))
return io_close(conn);
return io_read(conn, iod->in.cpkt->data, body_len, recv_body_negotiate,
neg);
}
static struct io_plan *receive_proof(struct io_conn *conn,
struct key_negotiate *neg)
{
return io_read(conn, &neg->iod->hdr_in, sizeof(neg->iod->hdr_in),
recv_header_negotiate, neg);
}
/* Steals w onto the returned Pkt */
static Pkt *pkt_wrap(const tal_t *ctx, void *w, Pkt__PktCase pkt_case)
{
Pkt *pkt = tal(ctx, Pkt);
pkt__init(pkt);
pkt->pkt_case = pkt_case;
/* Union, so any will do */
pkt->error = tal_steal(pkt, w);
return pkt;
}
static Pkt *authenticate_pkt(const tal_t *ctx,
const struct pubkey *node_id,
const secp256k1_ecdsa_signature *sig)
{
Authenticate *auth = tal(ctx, Authenticate);
authenticate__init(auth);
auth->node_id = pubkey_to_proto(auth, node_id);
auth->session_sig = signature_to_proto(auth, sig);
return pkt_wrap(ctx, auth, PKT__PKT_AUTH);
}
static struct io_plan *keys_exchanged(struct io_conn *conn,
struct key_negotiate *neg)
{
u8 shared_secret[32];
struct pubkey sessionkey;
secp256k1_ecdsa_signature sig;
Pkt *auth;
size_t totlen;
if (!pubkey_from_der(neg->their_sessionpubkey,
sizeof(neg->their_sessionpubkey),
&sessionkey)) {
log_unusual_blob(neg->log, "Bad sessionkey %s",
neg->their_sessionpubkey,
sizeof(neg->their_sessionpubkey));
return io_close(conn);
}
/* Derive shared secret. */
if (!secp256k1_ecdh(secp256k1_ctx, shared_secret,
&sessionkey.pubkey, neg->seckey)) {
log_unusual(neg->log, "Bad ECDH");
return io_close(conn);
}
/* Each side combines with their OWN session key to SENDING crypto. */
neg->iod = tal(neg, struct io_data);
setup_crypto(&neg->iod->in, shared_secret, neg->their_sessionpubkey);
setup_crypto(&neg->iod->out, shared_secret, neg->our_sessionpubkey);
/* FIXME-OLD #1:
*
* `session_sig` is the signature of the SHA256 of SHA256 of the its
* own sessionpubkey, using the secret key corresponding to the
* sender's `node_id`.
*/
privkey_sign(neg->dstate, neg->their_sessionpubkey,
sizeof(neg->their_sessionpubkey), &sig);
auth = authenticate_pkt(neg, &neg->dstate->id, &sig);
neg->iod->out.cpkt = encrypt_pkt(neg->iod, auth, &totlen);
return io_write(conn, neg->iod->out.cpkt, totlen, receive_proof, neg);
}
/* Read and ignore any extra bytes... */
static struct io_plan *discard_extra(struct io_conn *conn,
struct key_negotiate *neg)
{
size_t len = le32_to_cpu(neg->keylen);
/* FIXME-OLD#1: Additional fields MAY be added, and MUST be
* included in the `length` field. These MUST be ignored by
* implementations which do not understand them. */
if (len > sizeof(neg->their_sessionpubkey)) {
char *discard;
len -= sizeof(neg->their_sessionpubkey);
discard = tal_arr(neg, char, len);
log_unusual(neg->log,
"Ignoring %zu extra handshake bytes",
len);
return io_read(conn, discard, len, keys_exchanged, neg);
}
return keys_exchanged(conn, neg);
}
static struct io_plan *session_key_receive(struct io_conn *conn,
struct key_negotiate *neg)
{
/* FIXME-OLD#1: The `length` field is the length after the field
itself, and MUST be 33 or greater. */
if (le32_to_cpu(neg->keylen) < sizeof(neg->their_sessionpubkey)) {
log_unusual(neg->log, "short session key length %u",
le32_to_cpu(neg->keylen));
return io_close(conn);
}
/* FIXME-OLD#1: `length` MUST NOT exceed 1MB (1048576 bytes). */
if (le32_to_cpu(neg->keylen) > 1048576) {
log_unusual(neg->log,
"Oversize session key length %u",
le32_to_cpu(neg->keylen));
return io_close(conn);
}
log_debug(neg->log, "Session key length %u", le32_to_cpu(neg->keylen));
/* Now read their key. */
return io_read(conn, neg->their_sessionpubkey,
sizeof(neg->their_sessionpubkey), discard_extra, neg);
}
static struct io_plan *session_key_len_receive(struct io_conn *conn,
struct key_negotiate *neg)
{
/* Read the amount of data they will send.. */
return io_read(conn, &neg->keylen, sizeof(neg->keylen),
session_key_receive, neg);
}
static void gen_sessionkey(u8 seckey[32],
secp256k1_pubkey *pubkey)
{
do {
randombytes_buf(seckey, 32);
} while (!secp256k1_ec_pubkey_create(secp256k1_ctx, pubkey, seckey));
}
static struct io_plan *write_sessionkey(struct io_conn *conn,
struct key_negotiate *neg)
{
return io_write(conn, neg->our_sessionpubkey,
sizeof(neg->our_sessionpubkey),
session_key_len_receive, neg);
}
struct io_plan *peer_crypto_setup_(struct io_conn *conn,
struct lightningd_state *dstate,
const struct pubkey *id,
struct log *log,
struct io_plan *(*cb)(struct io_conn *conn,
struct lightningd_state *dstate,
struct io_data *iod,
struct log *log,
const struct pubkey *id,
void *arg),
void *arg)
{
size_t outputlen;
secp256k1_pubkey sessionkey;
struct key_negotiate *neg;
/* FIXME-OLD #1:
*
* The 4-byte length for each message is encrypted separately
* (resulting in a 20 byte header when the authentication tag
* is appended) */
BUILD_ASSERT(sizeof(struct crypto_pkt) == 20);
/* We store negotiation state here. */
neg = tal(conn, struct key_negotiate);
neg->cb = cb;
neg->arg = arg;
neg->dstate = dstate;
neg->expected_id = id;
neg->log = log;
gen_sessionkey(neg->seckey, &sessionkey);
outputlen = sizeof(neg->our_sessionpubkey);
secp256k1_ec_pubkey_serialize(secp256k1_ctx,
neg->our_sessionpubkey, &outputlen,
&sessionkey,
SECP256K1_EC_COMPRESSED);
assert(outputlen == sizeof(neg->our_sessionpubkey));
neg->keylen = cpu_to_le32(sizeof(neg->our_sessionpubkey));
return io_write(conn, &neg->keylen, sizeof(neg->keylen),
write_sessionkey, neg);
}

48
daemon/cryptopkt.h

@ -1,48 +0,0 @@
#ifndef LIGHTNING_DAEMON_CRYPTOPKT_H
#define LIGHTNING_DAEMON_CRYPTOPKT_H
#include "config.h"
#include "lightning.pb-c.h"
#include <ccan/io/io.h>
#include <ccan/typesafe_cb/typesafe_cb.h>
struct io_data;
struct json_connecting;
struct lightningd_state;
struct log;
struct peer;
struct io_plan *peer_crypto_setup_(struct io_conn *conn,
struct lightningd_state *dstate,
const struct pubkey *id,
struct log *log,
struct io_plan *(*cb)(struct io_conn *conn,
struct lightningd_state *dstate,
struct io_data *iod,
struct log *log,
const struct pubkey *id,
void *arg),
void *arg);
#define peer_crypto_setup(conn, dstate, id, log_, cb, arg) \
peer_crypto_setup_((conn), (dstate), (id), (log_), \
typesafe_cb_preargs(struct io_plan *, void *, \
(cb), (arg), \
struct io_conn *, \
struct lightningd_state *, \
struct io_data *, \
struct log *, \
const struct pubkey *), \
(arg))
/* Reads packet into peer->inpkt/peer->inpkt_len */
struct io_plan *peer_read_packet(struct io_conn *conn,
struct peer *peer,
struct io_plan *(*cb)(struct io_conn *,
struct peer *));
struct io_plan *peer_write_packet(struct io_conn *conn,
struct peer *peer,
const Pkt *pkt,
struct io_plan *(*next)(struct io_conn *,
struct peer *));
#endif /* LIGHTNING_DAEMON_CRYPTOPKT_H */

1980
daemon/db.c

File diff suppressed because it is too large

76
daemon/db.h

@ -1,76 +0,0 @@
#ifndef LIGHTNING_DAEMON_DB_H
#define LIGHTNING_DAEMON_DB_H
#include "config.h"
#include "peer.h"
#include <stdbool.h>
void db_init(struct lightningd_state *dstate);
void db_start_transaction(struct peer *peer);
void db_abort_transaction(struct peer *peer);
const char *db_commit_transaction(struct peer *peer);
void db_add_wallet_privkey(struct lightningd_state *dstate,
const struct privkey *privkey);
bool db_add_peer_address(struct lightningd_state *dstate,
const struct peer_address *addr);
/* Must NOT be inside transaction. */
bool db_update_their_closing(struct peer *peer);
bool db_new_pay_command(struct lightningd_state *dstate,
const struct sha256 *rhash,
const struct pubkey *ids,
u64 msatoshi,
const struct htlc *htlc);
bool db_replace_pay_command(struct lightningd_state *dstate,
const struct sha256 *rhash,
const struct pubkey *ids,
u64 msatoshi,
const struct htlc *htlc);
bool db_new_invoice(struct lightningd_state *dstate,
u64 msatoshi,
const char *label,
const struct preimage *r);
bool db_remove_invoice(struct lightningd_state *dstate,
const char *label);
/* FIXME: save error handling until db_commit_transaction for calls
* which have to be inside transaction anyway. */
/* Must be inside transaction. */
void db_create_peer(struct peer *peer);
void db_set_visible_state(struct peer *peer);
void db_set_anchor(struct peer *peer);
void db_new_htlc(struct peer *peer, const struct htlc *htlc);
void db_new_feechange(struct peer *peer, const struct feechange *feechange);
void db_htlc_fulfilled(struct peer *peer, const struct htlc *htlc);
void db_htlc_failed(struct peer *peer, const struct htlc *htlc);
void db_update_htlc_state(struct peer *peer, const struct htlc *htlc,
enum htlc_state oldstate);
void db_complete_pay_command(struct lightningd_state *dstate,
const struct htlc *htlc);
void db_resolve_invoice(struct lightningd_state *dstate,
const char *label, u64 paid_num);
void db_update_feechange_state(struct peer *peer,
const struct feechange *f,
enum feechange_state oldstate);
void db_remove_feechange(struct peer *peer, const struct feechange *feechange,
enum feechange_state oldstate);
void db_new_commit_info(struct peer *peer, enum side side,
const struct sha256 *prev_rhash);
void db_remove_their_prev_revocation_hash(struct peer *peer);
void db_update_next_revocation_hash(struct peer *peer);
void db_save_shachain(struct peer *peer);
void db_update_state(struct peer *peer);
void db_begin_shutdown(struct peer *peer);
void db_set_our_closing_script(struct peer *peer);
void db_update_our_closing(struct peer *peer);
void db_set_their_closing_script(struct peer *peer);
void db_add_commit_map(struct peer *peer,
const struct sha256_double *txid, u64 commit_num);
void db_forget_peer(struct peer *peer);
#endif /* LIGHTNING_DAEMON_DB_H */

2
daemon/dns.c

@ -2,7 +2,7 @@
#include "dns.h" #include "dns.h"
#include "lightningd.h" #include "lightningd.h"
#include "log.h" #include "log.h"
#include "peer.h" #include "netaddr.h"
#include <assert.h> #include <assert.h>
#include <ccan/err/err.h> #include <ccan/err/err.h>
#include <ccan/read_write_all/read_write_all.h> #include <ccan/read_write_all/read_write_all.h>

40
daemon/failure.c

@ -1,40 +0,0 @@
#include "failure.h"
#include "protobuf_convert.h"
#include <ccan/tal/str/str.h>
/* FIXME: Crypto! */
const u8 *failinfo_create(const tal_t *ctx,
const struct pubkey *id,
u32 error_code,
const char *reason)
{
FailInfo *f = tal(ctx, FailInfo);
u8 *arr;
fail_info__init(f);
f->id = pubkey_to_proto(f, id);
f->error_code = error_code;
if (reason)
f->reason = tal_strdup(f, reason);
else
f->reason = NULL;
arr = tal_arr(ctx, u8, fail_info__get_packed_size(f));
fail_info__pack(f, arr);
tal_free(f);
return arr;
}
FailInfo *failinfo_unwrap(const tal_t *ctx, const void *data, size_t len)
{
struct ProtobufCAllocator *prototal = make_prototal(ctx);
FailInfo *f;
f = fail_info__unpack(prototal, len, data);
if (f)
steal_from_prototal(ctx, prototal, f);
else
tal_free(prototal);
return f;
}

36
daemon/failure.h

@ -1,36 +0,0 @@
#ifndef LIGHTNING_DAEMON_FAILURE_H
#define LIGHTNING_DAEMON_FAILURE_H
#include "config.h"
#include "lightning.pb-c.h"
#include <ccan/short_types/short_types.h>
#include <ccan/tal/tal.h>
#include <secp256k1.h>
struct pubkey;
enum fail_error {
BAD_REQUEST_400 = 400,
UNAUTHORIZED_401 = 401,
PAYMENT_REQUIRED_402 = 402,
FORBIDDEN_403 = 403,
NOT_FOUND_404 = 404,
METHOD_NOT_ALLOWED_405 = 405,
REQUEST_TIMEOUT_408 = 408,
GONE_410 = 410,
IM_A_TEAPOT_418 = 418,
INTERNAL_SERVER_ERROR_500 = 500,
NOT_IMPLEMENTED_501 = 501,
BAD_GATEWAY_502 = 502,
SERVICE_UNAVAILABLE_503 = 503,
GATEWAY_TIMEOUT_504 = 504,
VERSION_NOT_SUPPORTED_505 = 505
};
const u8 *failinfo_create(const tal_t *ctx,
const struct pubkey *id,
enum fail_error error_code,
const char *reason);
FailInfo *failinfo_unwrap(const tal_t *ctx, const void *data, size_t len);
#endif /* LIGHTNING_DAEMON_FAILURE_H */

144
daemon/feechange.c

@ -1,144 +0,0 @@
#include "db.h"
#include "feechange.h"
#include "log.h"
#include "peer.h"
#include "peer_internal.h"
#include <ccan/array_size/array_size.h>
#include <inttypes.h>
#include "gen_feechange_state_names.h"
/* This is the HTLC-like flags for each state. */
static const int per_state_bits[] = {
[SENT_FEECHANGE] = HTLC_ADDING + HTLC_LOCAL_F_OWNER
+ HTLC_REMOTE_F_PENDING,
[SENT_FEECHANGE_COMMIT] = HTLC_ADDING + HTLC_LOCAL_F_OWNER
+ HTLC_REMOTE_F_COMMITTED
+ HTLC_REMOTE_F_WAS_COMMITTED,
[RCVD_FEECHANGE_REVOCATION] = HTLC_ADDING + HTLC_LOCAL_F_OWNER
+ HTLC_REMOTE_F_COMMITTED
+ HTLC_REMOTE_F_REVOKED
+ HTLC_LOCAL_F_PENDING
+ HTLC_REMOTE_F_WAS_COMMITTED,
[RCVD_FEECHANGE_ACK_COMMIT] = HTLC_ADDING + HTLC_LOCAL_F_OWNER
+ HTLC_REMOTE_F_COMMITTED
+ HTLC_REMOTE_F_REVOKED
+ HTLC_LOCAL_F_COMMITTED
+ HTLC_LOCAL_F_WAS_COMMITTED
+ HTLC_REMOTE_F_WAS_COMMITTED,
[SENT_FEECHANGE_ACK_REVOCATION] = HTLC_LOCAL_F_OWNER
+ HTLC_REMOTE_F_COMMITTED
+ HTLC_REMOTE_F_REVOKED
+ HTLC_LOCAL_F_COMMITTED
+ HTLC_LOCAL_F_REVOKED
+ HTLC_LOCAL_F_WAS_COMMITTED
+ HTLC_REMOTE_F_WAS_COMMITTED,
[RCVD_FEECHANGE] = HTLC_ADDING + HTLC_REMOTE_F_OWNER
+ HTLC_LOCAL_F_PENDING,
[RCVD_FEECHANGE_COMMIT] = HTLC_ADDING + HTLC_REMOTE_F_OWNER
+ HTLC_LOCAL_F_COMMITTED
+ HTLC_LOCAL_F_WAS_COMMITTED,
[SENT_FEECHANGE_REVOCATION] = HTLC_ADDING + HTLC_REMOTE_F_OWNER
+ HTLC_LOCAL_F_COMMITTED
+ HTLC_LOCAL_F_REVOKED
+ HTLC_REMOTE_F_PENDING
+ HTLC_LOCAL_F_WAS_COMMITTED,
[SENT_FEECHANGE_ACK_COMMIT] = HTLC_ADDING + HTLC_REMOTE_F_OWNER
+ HTLC_LOCAL_F_COMMITTED
+ HTLC_LOCAL_F_REVOKED
+ HTLC_REMOTE_F_COMMITTED
+ HTLC_LOCAL_F_WAS_COMMITTED
+ HTLC_REMOTE_F_WAS_COMMITTED,
[RCVD_FEECHANGE_ACK_REVOCATION] = HTLC_REMOTE_F_OWNER
+ HTLC_LOCAL_F_COMMITTED
+ HTLC_LOCAL_F_REVOKED
+ HTLC_REMOTE_F_COMMITTED
+ HTLC_REMOTE_F_REVOKED
+ HTLC_LOCAL_F_WAS_COMMITTED
+ HTLC_REMOTE_F_WAS_COMMITTED,
};
int feechange_state_flags(enum feechange_state state)
{
assert(state < ARRAY_SIZE(per_state_bits));
assert(per_state_bits[state]);
return per_state_bits[state];
}
const char *feechange_state_name(enum feechange_state s)
{
size_t i;
for (i = 0; enum_feechange_state_names[i].name; i++)
if (enum_feechange_state_names[i].v == s)
return enum_feechange_state_names[i].name;
return "unknown";
}
enum feechange_state feechange_state_from_name(const char *name)
{
size_t i;
for (i = 0; enum_feechange_state_names[i].name; i++)
if (streq(enum_feechange_state_names[i].name, name))
return enum_feechange_state_names[i].v;
return FEECHANGE_STATE_INVALID;
}
struct feechange *new_feechange(struct peer *peer,
u64 fee_rate,
enum feechange_state state)
{
struct feechange *f = tal(peer, struct feechange);
f->state = state;
f->fee_rate = fee_rate;
return f;
}
void feechange_changestate(struct peer *peer,
struct feechange *f,
enum feechange_state oldstate,
enum feechange_state newstate,
bool db_commit)
{
peer_debug(peer, "feechange: %s->%s",
feechange_state_name(f->state),
feechange_state_name(newstate));
assert(f->state == oldstate);
assert(peer->feechanges[f->state] == f);
/* You can only go to consecutive states. */
assert(newstate == f->state + 1);
/* You can't change sides. */
assert(feechange_side(f->state) == feechange_side(newstate));
f->state = newstate;
/* We can have multiple dead feestates, but only one in any other */
if (!feechange_is_dead(f))
assert(!peer->feechanges[f->state]);
peer->feechanges[oldstate] = NULL;
peer->feechanges[newstate] = f;
if (db_commit) {
if (newstate == RCVD_FEECHANGE_COMMIT
|| newstate == SENT_FEECHANGE_COMMIT)
db_new_feechange(peer, f);
else if (newstate == RCVD_FEECHANGE_ACK_REVOCATION
|| newstate == SENT_FEECHANGE_ACK_REVOCATION)
db_remove_feechange(peer, f, oldstate);
else
db_update_feechange_state(peer, f, oldstate);
}
}

52
daemon/feechange.h

@ -1,52 +0,0 @@
#ifndef LIGHTNING_DAEMON_FEECHANGE_H
#define LIGHTNING_DAEMON_FEECHANGE_H
#include "config.h"
#include "channel.h"
#include "feechange_state.h"
struct peer;
struct feechange {
/* What's the status */
enum feechange_state state;
/* The rate. */
u64 fee_rate;
};
static inline enum side feechange_side(enum feechange_state state)
{
if (state <= SENT_FEECHANGE_ACK_REVOCATION) {
return LOCAL;
} else {
assert(state < FEECHANGE_STATE_INVALID);
return REMOTE;
}
}
void feechange_changestate(struct peer *peer,
struct feechange *feechange,
enum feechange_state oldstate,
enum feechange_state newstate,
bool db_commit);
struct feechange *new_feechange(struct peer *peer,
u64 fee_rate,
enum feechange_state state);
const char *feechange_state_name(enum feechange_state s);
enum feechange_state feechange_state_from_name(const char *name);
/* HTLC-add-style bitflags for each feechange state */
int feechange_state_flags(enum feechange_state state);
static inline bool feechange_has(const struct feechange *f, int flag)
{
return feechange_state_flags(f->state) & flag;
}
static inline bool feechange_is_dead(const struct feechange *feechange)
{
return feechange->state == SENT_FEECHANGE_ACK_REVOCATION
|| feechange->state == RCVD_FEECHANGE_ACK_REVOCATION;
}
#endif /* LIGHTNING_DAEMON_FEECHANGE_H */

23
daemon/feechange_state.h

@ -1,23 +0,0 @@
#ifndef LIGHTNING_DAEMON_FEECHANGE_STATE_H
#define LIGHTNING_DAEMON_FEECHANGE_STATE_H
#include "config.h"
/* Like HTLCs, but only adding; we never "remove" a feechange. */
enum feechange_state {
/* When we add a new feechange, it goes in this order. */
SENT_FEECHANGE,
SENT_FEECHANGE_COMMIT,
RCVD_FEECHANGE_REVOCATION,
RCVD_FEECHANGE_ACK_COMMIT,
SENT_FEECHANGE_ACK_REVOCATION,
/* When they add a new feechange, it goes in this order. */
RCVD_FEECHANGE,
RCVD_FEECHANGE_COMMIT,
SENT_FEECHANGE_REVOCATION,
SENT_FEECHANGE_ACK_COMMIT,
RCVD_FEECHANGE_ACK_REVOCATION,
FEECHANGE_STATE_INVALID
};
#endif /* LIGHTNING_DAEMON_FEECHANGE_STATE_H */

81
daemon/htlc.c

@ -1,81 +0,0 @@
#include "db.h"
#include "htlc.h"
#include "log.h"
#include "peer.h"
#include "peer_internal.h"
#include "type_to_string.h"
#include <bitcoin/preimage.h>
#include <ccan/tal/str/str.h>
#include <inttypes.h>
void htlc_changestate(struct htlc *h,
enum htlc_state oldstate,
enum htlc_state newstate,
bool db_commit)
{
peer_debug(h->peer, "htlc %"PRIu64": %s->%s", h->id,
htlc_state_name(h->state), htlc_state_name(newstate));
assert(h->state == oldstate);
/* You can only go to consecutive states. */
assert(newstate == h->state + 1);
/* You can't change sides. */
assert((htlc_state_flags(h->state)&(HTLC_LOCAL_F_OWNER|HTLC_REMOTE_F_OWNER))
== (htlc_state_flags(newstate)&(HTLC_LOCAL_F_OWNER|HTLC_REMOTE_F_OWNER)));
h->state = newstate;
if (db_commit) {
if (newstate == RCVD_ADD_COMMIT || newstate == SENT_ADD_COMMIT) {
db_new_htlc(h->peer, h);
return;
}
/* These never hit the database. */
if (oldstate == RCVD_REMOVE_HTLC)
oldstate = SENT_ADD_ACK_REVOCATION;
else if (oldstate == SENT_REMOVE_HTLC)
oldstate = RCVD_ADD_ACK_REVOCATION;
db_update_htlc_state(h->peer, h, oldstate);
}
}
void htlc_undostate(struct htlc *h,
enum htlc_state oldstate,
enum htlc_state newstate)
{
log_debug(h->peer->log, "htlc %"PRIu64": %s->%s", h->id,
htlc_state_name(h->state), htlc_state_name(newstate));
assert(h->state == oldstate);
/* You can only return to previous state. */
assert(newstate == h->state - 1);
/* And must only be proposal, not commit. */
assert(h->state == SENT_REMOVE_HTLC || h->state == RCVD_REMOVE_HTLC);
/* You can't change sides. */
assert((htlc_state_flags(h->state)&(HTLC_LOCAL_F_OWNER|HTLC_REMOTE_F_OWNER))
== (htlc_state_flags(newstate)&(HTLC_LOCAL_F_OWNER|HTLC_REMOTE_F_OWNER)));
h->state = newstate;
}
static char *fmt_htlc(const tal_t *ctx, const struct htlc *h)
{
return tal_fmt(ctx, "{ id=%"PRIu64
" msatoshi=%"PRIu64
" expiry=%s"
" rhash=%s"
" rval=%s"
" src=%s }",
h->id, h->msatoshi,
type_to_string(ctx, struct abs_locktime, &h->expiry),
type_to_string(ctx, struct sha256, &h->rhash),
h->r ? tal_hexstr(ctx, h->r, sizeof(*h->r))
: "UNKNOWN",
h->src ? type_to_string(ctx, struct pubkey,
h->src->peer->id)
: "local");
}
REGISTER_TYPE_TO_STRING(htlc, fmt_htlc);

9
daemon/invoice.c

@ -102,6 +102,15 @@ static void tell_waiter(struct command *cmd, const struct invoice *paid)
command_success(cmd, response); command_success(cmd, response);
} }
/* UNIFICATION FIXME */
void db_resolve_invoice(struct lightningd_state *dstate,
const char *label, u64 paid_num);
bool db_new_invoice(struct lightningd_state *dstate,
u64 msatoshi,
const char *label,
const struct preimage *r);
bool db_remove_invoice(struct lightningd_state *dstate, const char *label);
void resolve_invoice(struct lightningd_state *dstate, struct invoice *invoice) void resolve_invoice(struct lightningd_state *dstate, struct invoice *invoice)
{ {
struct invoice_waiter *w; struct invoice_waiter *w;

280
daemon/irc_announce.c

@ -1,280 +0,0 @@
#include "bitcoin/privkey.h"
#include "bitcoin/signature.h"
#include "daemon/chaintopology.h"
#include "daemon/irc_announce.h"
#include "daemon/lightningd.h"
#include "daemon/log.h"
#include "daemon/peer.h"
#include "daemon/peer_internal.h"
#include "daemon/routing.h"
#include "daemon/secrets.h"
#include "daemon/timeout.h"
#include "utils.h"
#include <ccan/list/list.h>
#include <ccan/str/hex/hex.h>
/* Sign a privmsg by prepending the signature to the message */
static void sign_privmsg(struct ircstate *state, struct privmsg *msg)
{
int siglen;
u8 der[72];
secp256k1_ecdsa_signature sig;
privkey_sign(state->dstate, msg->msg, strlen(msg->msg), &sig);
siglen = signature_to_der(der, &sig);
msg->msg = tal_fmt(msg, "%s %s", tal_hexstr(msg, der, siglen), msg->msg);
}
static bool announce_channel(const tal_t *ctx, struct ircstate *state, struct peer *p)
{
char txid[65];
struct privmsg *msg = talz(ctx, struct privmsg);
struct txlocator *loc = locate_tx(ctx, state->dstate->topology, &p->anchor.txid);
if (loc == NULL)
return false;
bitcoin_txid_to_hex(&p->anchor.txid, txid, sizeof(txid));
msg->channel = "#lightning-nodes";
msg->msg = tal_fmt(
msg, "CHAN %s %s %s %d %d %d %d %d",
pubkey_to_hexstr(msg, &state->dstate->id),
pubkey_to_hexstr(msg, p->id),
txid,
loc->blkheight,
loc->index,
state->dstate->config.fee_base,
state->dstate->config.fee_per_satoshi,
state->dstate->config.min_htlc_expiry
);
sign_privmsg(state, msg);
irc_send_msg(state, msg);
return true;
}
/* Send an announcement for this node to the channel, including its
* hostname, port and ID */
static void announce_node(const tal_t *ctx, struct ircstate *state)
{
char *hostname = state->dstate->external_ip;
int port = state->dstate->portnum;
struct privmsg *msg = talz(ctx, struct privmsg);
if (hostname == NULL) {
//FIXME: log that we don't know our IP yet.
return;
}
msg->channel = "#lightning-nodes";
msg->msg = tal_fmt(
msg, "NODE %s %s %d",
pubkey_to_hexstr(msg, &state->dstate->id),
hostname,
port
);
sign_privmsg(state, msg);
irc_send_msg(state, msg);
}
/* Announce the node's contact information and all of its channels */
static void announce(struct ircstate *state)
{
tal_t *ctx = tal(state, tal_t);
struct peer *p;
announce_node(ctx, state);
list_for_each(&state->dstate->peers, p, list) {
if (!state_is_normal(p->state))
continue;
announce_channel(ctx, state, p);
}
tal_free(ctx);
/* By default we announce every 6 hours, otherwise when someone joins */
log_debug(state->log, "Setting long announce time: 6 hours");
state->dstate->announce = new_reltimer(&state->dstate->timers, state,
time_from_sec(3600 * 6),
announce, state);
}
/* Reconnect to IRC server upon disconnection. */
static void handle_irc_disconnect(struct ircstate *state)
{
/* Stop announcing. */
state->dstate->announce = tal_free(state->dstate->announce);
new_reltimer(&state->dstate->timers, state, state->reconnect_timeout,
irc_connect, state);
}
/* Verify a signed privmsg */
static bool verify_signed_privmsg(
struct ircstate *istate,
const struct pubkey *pk,
const struct privmsg *msg)
{
secp256k1_ecdsa_signature sig;
struct sha256_double hash;
const char *m = msg->msg + 1;
int siglen = strchr(m, ' ') - m;
const char *content = m + siglen + 1;
u8 *der = tal_hexdata(msg, m, siglen);
siglen = hex_data_size(siglen);
if (der == NULL)
return false;
if (!signature_from_der(der, siglen, &sig))
return false;
sha256_double(&hash, content, strlen(content));
return check_signed_hash(&hash, &sig, pk);
}
static void handle_irc_channel_announcement(
struct ircstate *istate,
const struct privmsg *msg,
char **splits)
{
struct pubkey *pk1 = talz(msg, struct pubkey);
struct pubkey *pk2 = talz(msg, struct pubkey);
struct sha256_double *txid = talz(msg, struct sha256_double);
int index;
bool ok = true;
int blkheight;
ok &= pubkey_from_hexstr(splits[1], strlen(splits[1]), pk1);
ok &= pubkey_from_hexstr(splits[2], strlen(splits[2]), pk2);
ok &= bitcoin_txid_from_hex(splits[3], strlen(splits[3]), txid);
blkheight = atoi(splits[4]);
index = atoi(splits[5]);
if (!ok || index < 0 || blkheight < 0) {
log_debug(istate->dstate->base_log, "Unable to parse channel announcent.");
return;
}
if (!verify_signed_privmsg(istate, pk1, msg)) {
log_debug(istate->log,
"Ignoring announcement from %s, signature check failed.",
splits[1]);
return;
}
/*
* FIXME Check in topology that the tx is in the block and
* that the endpoints match.
*/
add_connection(istate->dstate->rstate, pk1, pk2, atoi(splits[6]),
atoi(splits[7]), atoi(splits[8]), 6);
}
static void handle_irc_node_announcement(
struct ircstate *istate,
const struct privmsg *msg,
char **splits)
{
struct pubkey *pk = talz(msg, struct pubkey);
if (!pubkey_from_hexstr(splits[1], strlen(splits[1]), pk))
return;
if (!verify_signed_privmsg(istate, pk, msg)) {
log_debug(istate->log, "Ignoring node announcement from %s, signature check failed.",
splits[1]);
return;
} else if(splits[4] != NULL && strlen(splits[4]) > 64) {
log_debug(istate->log, "Ignoring node announcement from %s, alias too long",
splits[1]);
}
struct node *node = add_node(istate->dstate->rstate, pk);
if (splits[4] != NULL){
tal_free(node->alias);
node->alias = tal_hexdata(node, splits[4], strlen(splits[4]));
}
}
/*
* Handle an incoming message by checking if it is a channel
* announcement, parse it and add the channel to the topology if yes.
*
* The format for a valid announcement is:
* <sig> CHAN <pk1> <pk2> <anchor txid> <block height> <tx position> <base_fee>
* <proportional_fee> <locktime>
*/
static void handle_irc_privmsg(struct ircstate *istate, const struct privmsg *msg)
{
char **splits = tal_strsplit(msg, msg->msg + 1, " ", STR_NO_EMPTY);
int splitcount = tal_count(splits) - 1;
if (splitcount < 2)
return;
char *type = splits[1];
if (splitcount == 10 && streq(type, "CHAN"))
handle_irc_channel_announcement(istate, msg, splits + 1);
else if (splitcount >= 5 && streq(type, "NODE"))
handle_irc_node_announcement(istate, msg, splits + 1);
}
static void handle_irc_command(struct ircstate *istate, const struct irccommand *cmd)
{
struct lightningd_state *dstate = istate->dstate;
char **params = tal_strsplit(cmd, cmd->params, " ", STR_NO_EMPTY);
if (streq(cmd->command, "338") && tal_count(params) >= 4) {
dstate->external_ip = tal_strdup(
istate->dstate, params[3]);
log_debug(dstate->base_log, "Detected my own IP as %s", dstate->external_ip);
// Add our node to the node_map for completeness
add_node(istate->dstate->rstate, &dstate->id);
} else if (streq(cmd->command, "JOIN")) {
unsigned int delay;
/* Throw away any existing announce timer, and announce within
* 60 seconds. */
dstate->announce = tal_free(dstate->announce);
delay = pseudorand(60000000);
log_debug(istate->log, "Setting new announce time %u sec",
delay / 1000000);
dstate->announce = new_reltimer(&dstate->timers, istate,
time_from_usec(delay),
announce, istate);
}
}
static void handle_irc_connected(struct ircstate *istate)
{
irc_send(istate, "JOIN", "#lightning-nodes");
irc_send(istate, "WHOIS", "%s", istate->nick);
}
void setup_irc_connection(struct lightningd_state *dstate)
{
// Register callback
irc_privmsg_cb = *handle_irc_privmsg;
irc_connect_cb = *handle_irc_connected;
irc_disconnect_cb = *handle_irc_disconnect;
irc_command_cb = *handle_irc_command;
struct ircstate *state = talz(dstate, struct ircstate);
state->dstate = dstate;
state->server = "irc.lfnet.org";
state->reconnect_timeout = time_from_sec(15);
state->log = new_log(state, state->dstate->log_book, "%s:irc",
log_prefix(state->dstate->base_log));
/* Truncate nick at 13 bytes, would be imposed by freenode anyway */
state->nick = tal_fmt(
state,
"N%.12s",
pubkey_to_hexstr(state, &dstate->id) + 1);
/* We will see our own JOIN message, which will trigger announce */
irc_connect(state);
}

9
daemon/irc_announce.h

@ -1,9 +0,0 @@
#ifndef LIGHTNING_DAEMON_IRC_ANNOUNCE_H
#define LIGHTNING_DAEMON_IRC_ANNOUNCE_H
#include "config.h"
#include "irc.h"
// Main entrypoint for the lightning daemon
void setup_irc_connection(struct lightningd_state *dstate);
#endif /* LIGHTNING_DAEMON_IRC_ANNOUNCE_H */

4
daemon/jsonrpc.c

@ -5,7 +5,6 @@
#include "jsonrpc.h" #include "jsonrpc.h"
#include "lightningd.h" #include "lightningd.h"
#include "log.h" #include "log.h"
#include "peer.h"
#include "version.h" #include "version.h"
#include <ccan/array_size/array_size.h> #include <ccan/array_size/array_size.h>
#include <ccan/err/err.h> #include <ccan/err/err.h>
@ -231,6 +230,9 @@ static const struct json_command dev_crash_command = {
}; };
AUTODATA(json_command, &dev_crash_command); AUTODATA(json_command, &dev_crash_command);
/* UNIFICATION FIXME */
void debug_dump_peers(struct lightningd_state *dstate);
static void json_restart(struct command *cmd, static void json_restart(struct command *cmd,
const char *buffer, const jsmntok_t *params) const char *buffer, const jsmntok_t *params)
{ {

174
daemon/lightningd.c

@ -1,174 +0,0 @@
#include "bitcoind.h"
#include "chaintopology.h"
#include "db.h"
#include "invoice.h"
#include "irc_announce.h"
#include "jsonrpc.h"
#include "lightningd.h"
#include "log.h"
#include "options.h"
#include "p2p_announce.h"
#include "peer.h"
#include "routing.h"
#include "secrets.h"
#include "timeout.h"
#include "utils.h"
#include <bitcoin/chainparams.h>
#include <ccan/container_of/container_of.h>
#include <ccan/err/err.h>
#include <ccan/io/io.h>
#include <ccan/opt/opt.h>
#include <ccan/tal/grab_file/grab_file.h>
#include <ccan/tal/str/str.h>
#include <ccan/tal/tal.h>
#include <ccan/time/time.h>
#include <ccan/timer/timer.h>
#include <errno.h>
#include <inttypes.h>
#include <signal.h>
#include <unistd.h>
#include <version.h>
static struct lightningd_state *lightningd_state(void)
{
struct lightningd_state *dstate = tal(NULL, struct lightningd_state);
struct sha256_double unused;
dstate->log_book = new_log_book(dstate, 20*1024*1024, LOG_INFORM);
dstate->base_log = new_log(dstate, dstate->log_book,
"lightningd(%u):", (int)getpid());
list_head_init(&dstate->peers);
list_head_init(&dstate->pay_commands);
dstate->portnum = 0;
dstate->testnet = true;
timers_init(&dstate->timers, time_mono());
list_head_init(&dstate->wallet);
list_head_init(&dstate->addresses);
dstate->dev_never_routefail = false;
dstate->rstate = new_routing_state(dstate, dstate->base_log, &unused);
dstate->reexec = NULL;
dstate->external_ip = NULL;
dstate->announce = NULL;
dstate->invoices = invoices_init(dstate);
return dstate;
}
static void json_lightningd_dev_broadcast(struct command *cmd,
const char *buffer,
const jsmntok_t *params)
{
json_dev_broadcast(cmd, cmd->dstate->topology, buffer, params);
}
static const struct json_command dev_broadcast_command = {
"dev-broadcast",
json_lightningd_dev_broadcast,
"Pretend we broadcast txs, but don't send to bitcoind",
"Returns an empty result on success (waits for flush if enabled)"
};
AUTODATA(json_command, &dev_broadcast_command);
int main(int argc, char *argv[])
{
struct lightningd_state *dstate = lightningd_state();
err_set_progname(argv[0]);
if (!streq(protobuf_c_version(), PROTOBUF_C_VERSION))
errx(1, "Compiled against protobuf %s, but have %s",
PROTOBUF_C_VERSION, protobuf_c_version());
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY
| SECP256K1_CONTEXT_SIGN);
dstate->topology = new_topology(dstate, dstate->base_log);
dstate->bitcoind = new_bitcoind(dstate, dstate->base_log);
dstate->bitcoind->chainparams = chainparams_for_network("regtest");
/* Handle options and config; move to .lightningd */
register_opts(dstate);
handle_opts(dstate, argc, argv);
/* Now we can set chain_hash properly. */
dstate->rstate->chain_hash
= dstate->bitcoind->chainparams->genesis_blockhash;
/* Activate crash log now we're in the right place. */
crashlog_activate(dstate->base_log);
/* Ignore SIGPIPE: we look at our write return values*/
signal(SIGPIPE, SIG_IGN);
/* Set up node ID and private key. */
secrets_init(dstate);
new_node(dstate->rstate, &dstate->id);
/* Read or create database. */
db_init(dstate);
/* Initialize block topology. */
setup_topology(dstate->topology, dstate->bitcoind, &dstate->timers,
dstate->config.poll_time,
get_peer_min_block(dstate));
/* Create RPC socket (if any) */
setup_jsonrpc(dstate, dstate->rpc_filename);
/* Set up connections from peers (if dstate->portnum is set) */
setup_listeners(dstate);
/* set up IRC peer discovery */
if (dstate->config.use_irc)
setup_irc_connection(dstate);
/* set up P2P gossip protocol */
setup_p2p_announce(dstate);
log_info(dstate->base_log, "Hello world!");
/* If we loaded peers from database, reconnect now. */
reconnect_peers(dstate);
/* And send out anchors again if we're waiting. */
rebroadcast_anchors(dstate);
for (;;) {
struct timer *expired;
void *v = io_loop(&dstate->timers, &expired);
/* We use io_break(dstate) to shut down. */
if (v == dstate)
break;
if (expired)
timer_expired(dstate, expired);
else
cleanup_peers(dstate);
}
if (dstate->reexec) {
int fd;
log_unusual(dstate->base_log, "Restart at user request");
fflush(stdout);
fflush(stderr);
/* Manually close all fds (or near enough!) */
for (fd = 3; fd < 1024; fd++)
close(fd);
if (dstate->dev_never_routefail) {
size_t n = tal_count(dstate->reexec);
tal_resizez(&dstate->reexec, n+1);
dstate->reexec[n-1] = "--dev-no-routefail";
}
execvp(dstate->reexec[0], dstate->reexec);
fatal("Exec '%s' failed: %s",
dstate->reexec[0], strerror(errno));
}
tal_free(dstate);
opt_free_table();
return 0;
}

36
daemon/names.c

@ -1,36 +0,0 @@
#include "names.h"
#include <ccan/str/str.h>
/* Indented for 'check-source' because it has to be included after names.h */
#include "daemon/gen_state_names.h"
#include "daemon/gen_pkt_names.h"
const char *state_name(enum state s)
{
size_t i;
for (i = 0; enum_state_names[i].name; i++)
if (enum_state_names[i].v == s)
return enum_state_names[i].name;
return "unknown";
}
enum state name_to_state(const char *name)
{
size_t i;
for (i = 0; enum_state_names[i].name; i++)
if (streq(name, enum_state_names[i].name))
return enum_state_names[i].v;
return STATE_MAX;
}
const char *pkt_name(Pkt__PktCase pkt)
{
size_t i;
for (i = 0; enum_PktCase_names[i].name; i++)
if (enum_PktCase_names[i].v == pkt)
return enum_PktCase_names[i].name;
return "unknown";
}

10
daemon/names.h

@ -1,10 +0,0 @@
#ifndef LIGHTNING_NAMES_H
#define LIGHTNING_NAMES_H
#include "config.h"
#include "lightning.pb-c.h"
#include "state_types.h"
const char *state_name(enum state s);
enum state name_to_state(const char *name);
const char *pkt_name(Pkt__PktCase pkt);
#endif /* LIGHTNING_NAMES_H */

80
daemon/output_to_htlc.c

@ -1,80 +0,0 @@
#include "commit_tx.h"
#include "output_to_htlc.h"
#include "peer.h"
#include "peer_internal.h"
/* FIXME: Array makes this O(n^2). Use a hash table. */
struct wscript_by_wpkh {
struct htlc *h;
const u8 *wscript;
struct sha256 hash;
};
struct htlc_output_map {
struct wscript_by_wpkh *wpkh;
};
struct htlc_output_map *get_htlc_output_map(const tal_t *ctx,
const struct peer *peer,
const struct sha256 *rhash,
enum side side,
unsigned int commit_num)
{
struct htlc_map_iter it;
struct htlc *h;
size_t i;
struct htlc_output_map *omap = tal(ctx, struct htlc_output_map);
/* FIXME: use commit_num to filter htlcs. */
if (side == LOCAL)
assert(commit_num <= peer->local.commit->commit_num);
else
assert(commit_num <= peer->remote.commit->commit_num);
omap->wpkh = tal_arr(omap, struct wscript_by_wpkh,
htlc_map_count(&peer->htlcs));
for (i = 0, h = htlc_map_first(&peer->htlcs, &it);
h;
h = htlc_map_next(&peer->htlcs, &it)) {
omap->wpkh[i].h = h;
omap->wpkh[i].wscript = wscript_for_htlc(omap, peer, h, rhash,
side);
sha256(&omap->wpkh[i].hash,
omap->wpkh[i].wscript,
tal_count(omap->wpkh[i].wscript));
i++;
}
tal_resize(&omap->wpkh, i);
return omap;
}
static struct wscript_by_wpkh *get_wpkh(struct htlc_output_map *omap,
const u8 *script)
{
size_t i;
if (!is_p2wsh(script))
return NULL;
for (i = 0; i < tal_count(omap->wpkh); i++) {
if (!memcmp(script + 2, omap->wpkh[i].hash.u.u8,
sizeof(omap->wpkh[i].hash)))
return &omap->wpkh[i];
}
return NULL;
}
/* Which wscript does this pay to? */
struct htlc *txout_get_htlc(struct htlc_output_map *omap,
const u8 *script,
const u8 **wscript)
{
struct wscript_by_wpkh *wpkh = get_wpkh(omap, script);
if (wpkh) {
*wscript = wpkh->wscript;
return wpkh->h;
}
return NULL;
}

20
daemon/output_to_htlc.h

@ -1,20 +0,0 @@
#ifndef LIGHTNING_DAEMON_OUTPUT_TO_HTLC_H
#define LIGHTNING_DAEMON_OUTPUT_TO_HTLC_H
#include "config.h"
#include "htlc.h"
struct peer;
struct sha256;
/* Get a map of HTLCs (including at least those at the given commit_num). */
struct htlc_output_map *get_htlc_output_map(const tal_t *ctx,
const struct peer *peer,
const struct sha256 *rhash,
enum side side,
unsigned int commit_num);
/* If this scriptPubkey pays to a HTLC, get the full wscript */
struct htlc *txout_get_htlc(struct htlc_output_map *omap,
const u8 *script, const u8 **wscript);
#endif /* LIGHTNING_DAEMON_OUTPUT_TO_HTLC_H */

231
daemon/p2p_announce.c

@ -1,231 +0,0 @@
#include "daemon/broadcast.h"
#include "daemon/chaintopology.h"
#include "daemon/log.h"
#include "daemon/p2p_announce.h"
#include "daemon/packets.h"
#include "daemon/peer.h"
#include "daemon/peer_internal.h"
#include "daemon/routing.h"
#include "daemon/secrets.h"
#include "daemon/timeout.h"
#include "utils.h"
#include <ccan/tal/str/str.h>
#include <ccan/tal/tal.h>
#include <secp256k1.h>
static void broadcast_channel_update(struct lightningd_state *dstate, struct peer *peer)
{
struct txlocator *loc;
u8 *serialized;
secp256k1_ecdsa_signature signature;
struct short_channel_id short_channel_id;
u32 timestamp = time_now().ts.tv_sec;
const tal_t *tmpctx = tal_tmpctx(dstate);
loc = locate_tx(tmpctx, dstate->topology, &peer->anchor.txid);
short_channel_id.blocknum = loc->blkheight;
short_channel_id.txnum = loc->index;
short_channel_id.outnum = peer->anchor.index;
/* Avoid triggering memcheck */
memset(&signature, 0, sizeof(signature));
serialized = towire_channel_update(tmpctx, &signature,
&dstate->rstate->chain_hash,
&short_channel_id,
timestamp,
pubkey_cmp(&dstate->id, peer->id) > 0,
dstate->config.min_htlc_expiry,
//FIXME(cdecker) Make the minimum HTLC configurable
1,
dstate->config.fee_base,
dstate->config.fee_per_satoshi);
privkey_sign(dstate, serialized + 66, tal_count(serialized) - 66,
&signature);
serialized = towire_channel_update(tmpctx, &signature,
&dstate->rstate->chain_hash,
&short_channel_id,
timestamp,
pubkey_cmp(&dstate->id, peer->id) > 0,
dstate->config.min_htlc_expiry,
1,
dstate->config.fee_base,
dstate->config.fee_per_satoshi);
u8 *tag = tal_arr(tmpctx, u8, 0);
towire_short_channel_id(&tag, &short_channel_id);
queue_broadcast(dstate->rstate->broadcasts, WIRE_CHANNEL_UPDATE, tag, serialized);
tal_free(tmpctx);
}
static void broadcast_node_announcement(struct lightningd_state *dstate)
{
u8 *serialized;
secp256k1_ecdsa_signature signature;
static const u8 rgb_color[3];
static const u8 alias[32];
u32 timestamp = time_now().ts.tv_sec;
const tal_t *tmpctx = tal_tmpctx(dstate);
u8 *address;
/* Are we listening for incoming connections at all? */
if (!dstate->external_ip || !dstate->portnum) {
tal_free(tmpctx);
return;
}
/* Avoid triggering memcheck */
memset(&signature, 0, sizeof(signature));
address = write_ip(tmpctx, dstate->external_ip, dstate->portnum);
serialized = towire_node_announcement(tmpctx, &signature,
NULL,
timestamp,
&dstate->id, rgb_color, alias,
address);
privkey_sign(dstate, serialized + 66, tal_count(serialized) - 66,
&signature);
serialized = towire_node_announcement(tmpctx, &signature,
NULL,
timestamp,
&dstate->id, rgb_color, alias,
address);
u8 *tag = tal_arr(tmpctx, u8, 0);
towire_pubkey(&tag, &dstate->id);
queue_broadcast(dstate->rstate->broadcasts, WIRE_NODE_ANNOUNCEMENT, tag,
serialized);
tal_free(tmpctx);
}
static void broadcast_channel_announcement(struct lightningd_state *dstate, struct peer *peer)
{
struct txlocator *loc;
struct short_channel_id short_channel_id;
secp256k1_ecdsa_signature node_signature[2];
secp256k1_ecdsa_signature bitcoin_signature[2];
const struct pubkey *node_id[2];
const struct pubkey *bitcoin_key[2];
secp256k1_ecdsa_signature *my_node_signature;
secp256k1_ecdsa_signature *my_bitcoin_signature;
u8 *serialized;
const tal_t *tmpctx = tal_tmpctx(dstate);
loc = locate_tx(tmpctx, dstate->topology, &peer->anchor.txid);
short_channel_id.blocknum = loc->blkheight;
short_channel_id.txnum = loc->index;
short_channel_id.outnum = peer->anchor.index;
/* Set all sigs to zero */
memset(node_signature, 0, sizeof(node_signature));
memset(bitcoin_signature, 0, sizeof(bitcoin_signature));
//FIXME(cdecker) Copy remote stored signatures into place
if (pubkey_cmp(&dstate->id, peer->id) > 0) {
node_id[0] = peer->id;
node_id[1] = &dstate->id;
bitcoin_key[0] = peer->id;
bitcoin_key[1] = &dstate->id;
my_node_signature = &node_signature[1];
my_bitcoin_signature = &bitcoin_signature[1];
} else {
node_id[1] = peer->id;
node_id[0] = &dstate->id;
bitcoin_key[1] = peer->id;
bitcoin_key[0] = &dstate->id;
my_node_signature = &node_signature[0];
my_bitcoin_signature = &bitcoin_signature[0];
}
/* Sign the node_id with the bitcoin_key, proves delegation */
serialized = tal_arr(tmpctx, u8, 0);
towire_pubkey(&serialized, &dstate->id);
privkey_sign(dstate, serialized, tal_count(serialized), my_bitcoin_signature);
/* BOLT #7:
*
* The creating node MUST compute the double-SHA256 hash `h` of the
* message, starting at offset 256, up to the end of the message.
*/
serialized = towire_channel_announcement(tmpctx, &node_signature[0],
&node_signature[1],
&bitcoin_signature[0],
&bitcoin_signature[1],
NULL,
&dstate->rstate->chain_hash,
&short_channel_id,
node_id[0],
node_id[1],
bitcoin_key[0],
bitcoin_key[1]);
privkey_sign(dstate, serialized + 256, tal_count(serialized) - 256, my_node_signature);
serialized = towire_channel_announcement(tmpctx, &node_signature[0],
&node_signature[1],
&bitcoin_signature[0],
&bitcoin_signature[1],
NULL,
&dstate->rstate->chain_hash,
&short_channel_id,
node_id[0],
node_id[1],
bitcoin_key[0],
bitcoin_key[1]);
u8 *tag = tal_arr(tmpctx, u8, 0);
towire_short_channel_id(&tag, &short_channel_id);
queue_broadcast(dstate->rstate->broadcasts, WIRE_CHANNEL_ANNOUNCEMENT,
tag, serialized);
tal_free(tmpctx);
}
static void announce(struct lightningd_state *dstate)
{
struct peer *p;
int nchan = 0;
new_reltimer(&dstate->timers, dstate, time_from_sec(5*60*60), announce, dstate);
list_for_each(&dstate->peers, p, list) {
if (state_is_normal(p->state)) {
broadcast_channel_announcement(dstate, p);
broadcast_channel_update(dstate, p);
nchan += 1;
}
}
/* No point in broadcasting our node if we don't have a channel */
if (nchan > 0)
broadcast_node_announcement(dstate);
}
void announce_channel(struct lightningd_state *dstate, struct peer *peer)
{
broadcast_channel_announcement(dstate, peer);
broadcast_channel_update(dstate, peer);
broadcast_node_announcement(dstate);
}
static void process_broadcast_queue(struct lightningd_state *dstate)
{
struct peer *p;
struct queued_message *msg;
new_reltimer(&dstate->timers, dstate, time_from_sec(30), process_broadcast_queue, dstate);
list_for_each(&dstate->peers, p, list) {
if (!state_is_normal(p->state))
continue;
msg = next_broadcast_message(dstate->rstate->broadcasts,
&p->broadcast_index);
while (msg != NULL) {
queue_pkt_nested(p, msg->type, msg->payload);
msg = next_broadcast_message(dstate->rstate->broadcasts,
&p->broadcast_index);
}
}
}
void setup_p2p_announce(struct lightningd_state *dstate)
{
new_reltimer(&dstate->timers, dstate, time_from_sec(5*60*60), announce, dstate);
new_reltimer(&dstate->timers, dstate, time_from_sec(30), process_broadcast_queue, dstate);
}

15
daemon/p2p_announce.h

@ -1,15 +0,0 @@
#ifndef LIGHTNING_DAEMON_P2P_ANNOUNCE_H
#define LIGHTNING_DAEMON_P2P_ANNOUNCE_H
#include "config.h"
#include "daemon/broadcast.h"
#include "daemon/lightningd.h"
#include "daemon/routing.h"
#include "lightningd.h"
#include "wire/gen_peer_wire.h"
void setup_p2p_announce(struct lightningd_state *dstate);
/* Used to announce the existence of a channel and the endpoints */
void announce_channel(struct lightningd_state *dstate, struct peer *peer);
#endif /* LIGHTNING_DAEMON_P2P_ANNOUNCE_H */

599
daemon/packets.c

@ -1,599 +0,0 @@
#include "bitcoin/preimage.h"
#include "bitcoin/script.h"
#include "bitcoin/tx.h"
#include "chaintopology.h"
#include "close_tx.h"
#include "commit_tx.h"
#include "cryptopkt.h"
#include "htlc.h"
#include "lightningd.h"
#include "log.h"
#include "names.h"
#include "packets.h"
#include "peer.h"
#include "peer_internal.h"
#include "protobuf_convert.h"
#include "secrets.h"
#include "state.h"
#include "utils.h"
#include <ccan/array_size/array_size.h>
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/io/io.h>
#include <ccan/mem/mem.h>
#include <ccan/ptrint/ptrint.h>
#include <ccan/str/hex/hex.h>
#include <ccan/structeq/structeq.h>
#include <ccan/tal/str/str.h>
#include <inttypes.h>
/* Wrap (and own!) member inside Pkt */
static Pkt *make_pkt(const tal_t *ctx, Pkt__PktCase type, const void *msg)
{
Pkt *pkt = tal(ctx, Pkt);
pkt__init(pkt);
pkt->pkt_case = type;
/* This is a union, so doesn't matter which we assign. */
pkt->error = (Error *)tal_steal(pkt, msg);
/* This makes sure all packets are valid. */
#ifndef NDEBUG
{
size_t len;
u8 *packed;
Pkt *cpy;
len = pkt__get_packed_size(pkt);
packed = tal_arr(pkt, u8, len);
pkt__pack(pkt, packed);
cpy = pkt__unpack(NULL, len, memcheck(packed, len));
assert(cpy);
pkt__free_unpacked(cpy, NULL);
tal_free(packed);
}
#endif
return pkt;
}
static void queue_raw_pkt(struct peer *peer, Pkt *pkt)
{
size_t n = tal_count(peer->outpkt);
tal_resize(&peer->outpkt, n+1);
peer->outpkt[n] = pkt;
log_debug(peer->log, "Queued pkt %s (order=%"PRIu64")",
pkt_name(pkt->pkt_case), peer->order_counter);
/* In case it was waiting for output. */
io_wake(peer);
}
static void queue_pkt(struct peer *peer, Pkt__PktCase type, const void *msg)
{
queue_raw_pkt(peer, make_pkt(peer, type, msg));
}
void queue_pkt_open(struct peer *peer, bool offer_anchor)
{
OpenChannel *o = tal(peer, OpenChannel);
open_channel__init(o);
o->revocation_hash = sha256_to_proto(o, &peer->local.commit->revocation_hash);
o->next_revocation_hash = sha256_to_proto(o, &peer->local.next_revocation_hash);
o->commit_key = pubkey_to_proto(o, &peer->local.commitkey);
o->final_key = pubkey_to_proto(o, &peer->local.finalkey);
o->delay = tal(o, Locktime);
locktime__init(o->delay);
o->delay->locktime_case = LOCKTIME__LOCKTIME_BLOCKS;
o->delay->blocks = rel_locktime_to_blocks(&peer->local.locktime);
o->initial_fee_rate = peer->local.commit_fee_rate;
if (offer_anchor)
o->anch = OPEN_CHANNEL__ANCHOR_OFFER__WILL_CREATE_ANCHOR;
else
o->anch = OPEN_CHANNEL__ANCHOR_OFFER__WONT_CREATE_ANCHOR;
o->min_depth = peer->local.mindepth;
queue_pkt(peer, PKT__PKT_OPEN, o);
}
void queue_pkt_anchor(struct peer *peer)
{
OpenAnchor *a = tal(peer, OpenAnchor);
open_anchor__init(a);
a->txid = sha256_to_proto(a, &peer->anchor.txid.sha);
a->output_index = peer->anchor.index;
a->amount = peer->anchor.satoshis;
queue_pkt(peer, PKT__PKT_OPEN_ANCHOR, a);
}
void queue_pkt_open_commit_sig(struct peer *peer)
{
OpenCommitSig *s = tal(peer, OpenCommitSig);
open_commit_sig__init(s);
s->sig = signature_to_proto(s, peer->remote.commit->sig);
queue_pkt(peer, PKT__PKT_OPEN_COMMIT_SIG, s);
}
void queue_pkt_open_complete(struct peer *peer)
{
OpenComplete *o = tal(peer, OpenComplete);
open_complete__init(o);
queue_pkt(peer, PKT__PKT_OPEN_COMPLETE, o);
}
void queue_pkt_htlc_add(struct peer *peer, struct htlc *htlc)
{
UpdateAddHtlc *u = tal(peer, UpdateAddHtlc);
update_add_htlc__init(u);
u->id = htlc->id;
u->amount_msat = htlc->msatoshi;
u->r_hash = sha256_to_proto(u, &htlc->rhash);
u->expiry = abs_locktime_to_proto(u, &htlc->expiry);
u->route = tal(u, Routing);
routing__init(u->route);
u->route->info.data = tal_dup_arr(u, u8,
htlc->routing,
tal_count(htlc->routing),
0);
u->route->info.len = tal_count(u->route->info.data);
queue_pkt(peer, PKT__PKT_UPDATE_ADD_HTLC, u);
}
void queue_pkt_htlc_fulfill(struct peer *peer, struct htlc *htlc)
{
UpdateFulfillHtlc *f = tal(peer, UpdateFulfillHtlc);
update_fulfill_htlc__init(f);
f->id = htlc->id;
f->r = preimage_to_proto(f, htlc->r);
queue_pkt(peer, PKT__PKT_UPDATE_FULFILL_HTLC, f);
}
void queue_pkt_htlc_fail(struct peer *peer, struct htlc *htlc)
{
UpdateFailHtlc *f = tal(peer, UpdateFailHtlc);
update_fail_htlc__init(f);
f->id = htlc->id;
f->reason = tal(f, FailReason);
fail_reason__init(f->reason);
f->reason->info.len = tal_count(htlc->fail);
f->reason->info.data = tal_dup_arr(f->reason, u8,
htlc->fail, f->reason->info.len, 0);
queue_pkt(peer, PKT__PKT_UPDATE_FAIL_HTLC, f);
}
void queue_pkt_feechange(struct peer *peer, u64 feerate)
{
UpdateFee *f = tal(peer, UpdateFee);
update_fee__init(f);
f->fee_rate = feerate;
queue_pkt(peer, PKT__PKT_UPDATE_FEE, f);
}
/* OK, we're sending a signature for their pending changes. */
void queue_pkt_commit(struct peer *peer, const secp256k1_ecdsa_signature *sig)
{
UpdateCommit *u = tal(peer, UpdateCommit);
/* Now send message */
update_commit__init(u);
if (sig)
u->sig = signature_to_proto(u, sig);
else
u->sig = NULL;
queue_pkt(peer, PKT__PKT_UPDATE_COMMIT, u);
}
/* Send a preimage for the old commit tx. The one we've just committed to is
* in peer->local.commit. */
void queue_pkt_revocation(struct peer *peer,
const struct sha256 *preimage,
const struct sha256 *next_hash)
{
UpdateRevocation *u = tal(peer, UpdateRevocation);
update_revocation__init(u);
u->revocation_preimage = sha256_to_proto(u, preimage);
u->next_revocation_hash = sha256_to_proto(u, next_hash);
queue_pkt(peer, PKT__PKT_UPDATE_REVOCATION, u);
}
/* Send a serialized nested packet. */
void queue_pkt_nested(struct peer *peer,
int type,
const u8 *nested_pkt)
{
NestedPkt *pb = tal(peer, NestedPkt);
nested_pkt__init(pb);
pb->type = type;
pb->inner_pkt.len = tal_count(nested_pkt);
pb->inner_pkt.data = tal_dup_arr(pb, u8, nested_pkt, pb->inner_pkt.len, 0);
queue_pkt(peer, PKT__PKT_NESTED, pb);
}
Pkt *pkt_err(struct peer *peer, const char *msg, ...)
{
Error *e = tal(peer, Error);
va_list ap;
error__init(e);
va_start(ap, msg);
e->problem = tal_vfmt(e, msg, ap);
va_end(ap);
log_unusual(peer->log, "Sending PKT_ERROR: %s", e->problem);
return make_pkt(peer, PKT__PKT_ERROR, e);
}
Pkt *pkt_init(struct peer *peer, u64 ack)
{
Init *i = tal(peer, Init);
init__init(i);
i->ack = ack;
/* FIXME-OLD #2:
*
* A node SHOULD set the `features` field of the `init`
* message to a bitset representing features it supports.
*/
/* No features yet! */
return make_pkt(peer, PKT__PKT_INIT, i);
}
void queue_pkt_err(struct peer *peer, Pkt *err)
{
queue_raw_pkt(peer, err);
}
void queue_pkt_close_shutdown(struct peer *peer)
{
CloseShutdown *c = tal(peer, CloseShutdown);
close_shutdown__init(c);
c->scriptpubkey.data = tal_dup_arr(c, u8,
peer->closing.our_script,
tal_count(peer->closing.our_script),
0);
c->scriptpubkey.len = tal_count(c->scriptpubkey.data);
queue_pkt(peer, PKT__PKT_CLOSE_SHUTDOWN, c);
}
void queue_pkt_close_signature(struct peer *peer)
{
CloseSignature *c = tal(peer, CloseSignature);
struct bitcoin_tx *close_tx;
secp256k1_ecdsa_signature our_close_sig;
close_signature__init(c);
close_tx = peer_create_close_tx(c, peer, peer->closing.our_fee);
peer_sign_mutual_close(peer, close_tx, &our_close_sig);
c->sig = signature_to_proto(c, &our_close_sig);
c->close_fee = peer->closing.our_fee;
log_info(peer->log, "queue_pkt_close_signature: offered close fee %"
PRIu64, c->close_fee);
queue_pkt(peer, PKT__PKT_CLOSE_SIGNATURE, c);
}
Pkt *pkt_err_unexpected(struct peer *peer, const Pkt *pkt)
{
return pkt_err(peer, "Unexpected packet %s", pkt_name(pkt->pkt_case));
}
/* Process various packets: return an error packet on failure. */
Pkt *accept_pkt_open(struct peer *peer, const Pkt *pkt,
struct sha256 *revocation_hash,
struct sha256 *next_revocation_hash)
{
struct rel_locktime locktime;
const OpenChannel *o = pkt->open;
u64 feerate = get_feerate(peer->dstate->topology);
if (!proto_to_rel_locktime(o->delay, &locktime))
return pkt_err(peer, "Invalid delay");
if (o->delay->locktime_case != LOCKTIME__LOCKTIME_BLOCKS)
return pkt_err(peer, "Delay in seconds not accepted");
if (o->delay->blocks > peer->dstate->config.locktime_max)
return pkt_err(peer, "Delay %u too great", o->delay->blocks);
if (o->min_depth > peer->dstate->config.anchor_confirms_max)
return pkt_err(peer, "min_depth %u too great", o->min_depth);
if (o->initial_fee_rate
< feerate * peer->dstate->config.commitment_fee_min_percent / 100)
return pkt_err(peer, "Commitment fee %u below %"PRIu64" x %u%%",
o->initial_fee_rate, feerate,
peer->dstate->config.commitment_fee_min_percent);
if (peer->dstate->config.commitment_fee_max_percent != 0
&& (o->initial_fee_rate
> feerate * peer->dstate->config.commitment_fee_max_percent/100))
return pkt_err(peer, "Commitment fee %u above %"PRIu64" x %u%%",
o->initial_fee_rate, feerate,
peer->dstate->config.commitment_fee_max_percent);
if (o->anch == OPEN_CHANNEL__ANCHOR_OFFER__WILL_CREATE_ANCHOR)
peer->remote.offer_anchor = true;
else if (o->anch == OPEN_CHANNEL__ANCHOR_OFFER__WONT_CREATE_ANCHOR)
peer->remote.offer_anchor = false;
else
return pkt_err(peer, "Unknown offer anchor value %u",
o->anch);
if (peer->remote.offer_anchor == peer->local.offer_anchor)
return pkt_err(peer, "Exactly one side can offer anchor (we %s)",
peer->local.offer_anchor ? "do" : "don't");
if (!proto_to_rel_locktime(o->delay, &peer->remote.locktime))
return pkt_err(peer, "Malformed locktime");
peer->remote.mindepth = o->min_depth;
peer->remote.commit_fee_rate = o->initial_fee_rate;
if (!proto_to_pubkey(o->commit_key, &peer->remote.commitkey))
return pkt_err(peer, "Bad commitkey");
if (!proto_to_pubkey(o->final_key, &peer->remote.finalkey))
return pkt_err(peer, "Bad finalkey");
proto_to_sha256(o->revocation_hash, revocation_hash);
proto_to_sha256(o->next_revocation_hash, next_revocation_hash);
return NULL;
}
Pkt *accept_pkt_anchor(struct peer *peer, const Pkt *pkt)
{
const OpenAnchor *a = pkt->open_anchor;
/* They must be offering anchor for us to try accepting */
assert(!peer->local.offer_anchor);
assert(peer->remote.offer_anchor);
if (anchor_too_large(a->amount))
return pkt_err(peer, "Anchor millisatoshis exceeds 32 bits");
proto_to_sha256(a->txid, &peer->anchor.txid.sha);
peer->anchor.index = a->output_index;
peer->anchor.satoshis = a->amount;
return NULL;
}
Pkt *accept_pkt_open_commit_sig(struct peer *peer, const Pkt *pkt,
secp256k1_ecdsa_signature *sig)
{
const OpenCommitSig *s = pkt->open_commit_sig;
if (!proto_to_signature(s->sig, sig))
return pkt_err(peer, "Malformed signature");
return NULL;
}
Pkt *accept_pkt_open_complete(struct peer *peer, const Pkt *pkt)
{
return NULL;
}
/*
* We add changes to both our staging cstate (as they did when they sent
* it) and theirs (as they will when we ack it).
*/
Pkt *accept_pkt_htlc_add(struct peer *peer, const Pkt *pkt, struct htlc **h)
{
const UpdateAddHtlc *u = pkt->update_add_htlc;
struct sha256 rhash;
struct abs_locktime expiry;
/* FIXME-OLD #2:
*
* `amount_msat` MUST BE greater than 0.
*/
if (u->amount_msat == 0)
return pkt_err(peer, "Invalid amount_msat");
proto_to_sha256(u->r_hash, &rhash);
if (!proto_to_abs_locktime(u->expiry, &expiry))
return pkt_err(peer, "Invalid HTLC expiry");
if (abs_locktime_is_seconds(&expiry))
return pkt_err(peer, "HTLC expiry in seconds not supported!");
/* FIXME-OLD #2:
*
* A node MUST NOT add a HTLC if it would result in it
* offering more than 300 HTLCs in the remote commitment transaction.
*/
if (peer->remote.staging_cstate->side[REMOTE].num_htlcs == 300)
return pkt_err(peer, "Too many HTLCs");
/* FIXME-OLD #2:
*
* A node MUST set `id` to a unique identifier for this HTLC
* amongst all past or future `update_add_htlc` messages.
*/
/* Note that it's not *our* problem if they do this, it's
* theirs (future confusion). Nonetheless, we detect and
* error for them. */
if (htlc_get(&peer->htlcs, u->id, REMOTE))
return pkt_err(peer, "HTLC id %"PRIu64" clashes for you", u->id);
/* FIXME-OLD #2:
*
* ...and the receiving node MUST add the HTLC addition to the
* unacked changeset for its local commitment. */
*h = peer_new_htlc(peer, u->id, u->amount_msat, &rhash,
abs_locktime_to_blocks(&expiry),
u->route->info.data, u->route->info.len,
NULL, RCVD_ADD_HTLC);
return NULL;
}
static Pkt *find_commited_htlc(struct peer *peer, uint64_t id,
struct htlc **local_htlc)
{
*local_htlc = htlc_get(&peer->htlcs, id, LOCAL);
/* FIXME-OLD #2:
*
* A node MUST check that `id` corresponds to an HTLC in its
* current commitment transaction, and MUST fail the
* connection if it does not.
*/
if (!(*local_htlc))
return pkt_err(peer, "Did not find HTLC %"PRIu64, id);
if ((*local_htlc)->state != SENT_ADD_ACK_REVOCATION)
return pkt_err(peer, "HTLC %"PRIu64" state %s", id,
htlc_state_name((*local_htlc)->state));
return NULL;
}
Pkt *accept_pkt_htlc_fail(struct peer *peer, const Pkt *pkt, struct htlc **h,
u8 **fail)
{
const UpdateFailHtlc *f = pkt->update_fail_htlc;
Pkt *err;
err = find_commited_htlc(peer, f->id, h);
if (err)
return err;
if ((*h)->r)
return pkt_err(peer, "HTLC %"PRIu64" already fulfilled",
(*h)->id);
*fail = tal_dup_arr(*h, u8, f->reason->info.data, f->reason->info.len,0);
return NULL;
}
Pkt *accept_pkt_htlc_fulfill(struct peer *peer, const Pkt *pkt, struct htlc **h,
struct preimage *r)
{
const UpdateFulfillHtlc *f = pkt->update_fulfill_htlc;
struct sha256 rhash;
Pkt *err;
err = find_commited_htlc(peer, f->id, h);
if (err)
return err;
/* Now, it must solve the HTLC rhash puzzle. */
proto_to_preimage(f->r, r);
sha256(&rhash, r, sizeof(*r));
if (!structeq(&rhash, &(*h)->rhash))
return pkt_err(peer, "Invalid r for %"PRIu64, f->id);
return NULL;
}
Pkt *accept_pkt_update_fee(struct peer *peer, const Pkt *pkt, u64 *feerate)
{
const UpdateFee *f = pkt->update_fee;
*feerate = f->fee_rate;
return NULL;
}
Pkt *accept_pkt_commit(struct peer *peer, const Pkt *pkt,
secp256k1_ecdsa_signature *sig)
{
const UpdateCommit *c = pkt->update_commit;
if (!c->sig && sig)
return pkt_err(peer, "Expected signature");
if (!sig && c->sig)
return pkt_err(peer, "Unexpected signature");
if (!sig && !c->sig)
return NULL;
if (!proto_to_signature(c->sig, sig))
return pkt_err(peer, "Malformed signature");
return NULL;
}
Pkt *accept_pkt_revocation(struct peer *peer, const Pkt *pkt)
{
const UpdateRevocation *r = pkt->update_revocation;
struct sha256 h, preimage;
assert(peer->their_prev_revocation_hash);
proto_to_sha256(r->revocation_preimage, &preimage);
/* FIXME-OLD #2:
*
* The receiver of `update_revocation` MUST check that the
* SHA256 hash of `revocation_preimage` matches the previous commitment
* transaction, and MUST fail if it does not.
*/
sha256(&h, &preimage, sizeof(preimage));
if (!structeq(&h, peer->their_prev_revocation_hash)) {
log_unusual(peer->log, "Incorrect preimage for %"PRIu64,
peer->remote.commit->commit_num - 1);
return pkt_err(peer, "complete preimage incorrect");
}
// save revocation preimages in shachain
if (!shachain_add_hash(&peer->their_preimages,
0xFFFFFFFFFFFFFFFFL
- (peer->remote.commit->commit_num - 1),
&preimage))
return pkt_err(peer, "preimage not next in shachain");
log_debug(peer->log, "Got revocation preimage %"PRIu64,
peer->remote.commit->commit_num - 1);
/* Clear the previous revocation hash. */
peer->their_prev_revocation_hash
= tal_free(peer->their_prev_revocation_hash);
/* Save next revocation hash. */
proto_to_sha256(r->next_revocation_hash,
&peer->remote.next_revocation_hash);
return NULL;
}
Pkt *accept_pkt_close_shutdown(struct peer *peer, const Pkt *pkt)
{
const CloseShutdown *c = pkt->close_shutdown;
peer->closing.their_script = tal_dup_arr(peer, u8,
c->scriptpubkey.data,
c->scriptpubkey.len, 0);
/* FIXME-OLD #2:
*
* 1. `OP_DUP` `OP_HASH160` `20` 20-bytes `OP_EQUALVERIFY` `OP_CHECKSIG`
* (pay to pubkey hash), OR
* 2. `OP_HASH160` `20` 20-bytes `OP_EQUAL` (pay to script hash), OR
* 3. `OP_0` `20` 20-bytes (version 0 pay to witness pubkey), OR
* 4. `OP_0` `32` 32-bytes (version 0 pay to witness script hash)
*
* A node receiving `close_shutdown` SHOULD fail the connection
* `script_pubkey` is not one of those forms.
*/
if (!is_p2pkh(peer->closing.their_script)
&& !is_p2sh(peer->closing.their_script)
&& !is_p2wpkh(peer->closing.their_script)
&& !is_p2wsh(peer->closing.their_script)) {
log_broken_blob(peer->log, "Bad script_pubkey %s",
peer->closing.their_script,
tal_count(peer->closing.their_script));
return pkt_err(peer, "Bad script_pubkey");
}
return NULL;
}

478
daemon/pay.c

@ -1,478 +0,0 @@
#include "chaintopology.h"
#include "db.h"
#include "failure.h"
#include "jsonrpc.h"
#include "lightningd.h"
#include "log.h"
#include "pay.h"
#include "peer.h"
#include "peer_internal.h"
#include "routing.h"
#include "sphinx.h"
#include <bitcoin/preimage.h>
#include <ccan/str/hex/hex.h>
#include <ccan/structeq/structeq.h>
#include <inttypes.h>
#include <sodium/randombytes.h>
/* Outstanding "pay" commands. */
struct pay_command {
struct list_node list;
struct sha256 rhash;
u64 msatoshi;
const struct pubkey *ids;
/* Set if this is in progress. */
struct htlc *htlc;
/* Preimage if this succeeded. */
const struct preimage *rval;
struct command *cmd;
};
static void json_pay_success(struct command *cmd, const struct preimage *rval)
{
struct json_result *response;
response = new_json_result(cmd);
json_object_start(response, NULL);
json_add_hex(response, "preimage", rval, sizeof(*rval));
json_object_end(response);
command_success(cmd, response);
}
static void handle_json(struct command *cmd, const struct htlc *htlc,
const FailInfo *f)
{
struct pubkey id;
const char *idstr = "INVALID";
if (htlc->r) {
json_pay_success(cmd, htlc->r);
return;
}
if (!f) {
command_fail(cmd, "failed (bad message)");
return;
}
if (proto_to_pubkey(f->id, &id))
idstr = pubkey_to_hexstr(cmd, &id);
command_fail(cmd,
"failed: error code %u node %s reason %s",
f->error_code, idstr, f->reason ? f->reason : "unknown");
}
static void check_routing_failure(struct lightningd_state *dstate,
const struct pay_command *pc,
const FailInfo *f)
{
size_t i;
struct pubkey id;
if (!f)
return;
/* FIXME: We remove route on *any* failure. */
log_debug(dstate->base_log, "Seeking route for fail code %u",
f->error_code);
if (!proto_to_pubkey(f->id, &id)) {
log_add(dstate->base_log, " - bad node");
return;
}
log_add_struct(dstate->base_log, " node %s", struct pubkey, &id);
/* Don't remove route if it's last node (obviously) */
for (i = 0; i+1 < tal_count(pc->ids); i++) {
if (structeq(&pc->ids[i], &id)) {
remove_connection(dstate->rstate, &pc->ids[i], &pc->ids[i+1]);
return;
}
}
if (structeq(&pc->ids[i], &id))
log_debug(dstate->base_log, "Final node: ignoring");
else
log_debug(dstate->base_log, "Node not on route: ignoring");
}
void complete_pay_command(struct lightningd_state *dstate,
const struct htlc *htlc)
{
struct pay_command *i;
list_for_each(&dstate->pay_commands, i, list) {
if (i->htlc == htlc) {
FailInfo *f = NULL;
db_complete_pay_command(dstate, htlc);
if (htlc->r)
i->rval = tal_dup(i, struct preimage, htlc->r);
else {
f = failinfo_unwrap(i->cmd, htlc->fail,
tal_count(htlc->fail));
check_routing_failure(dstate, i, f);
}
/* No longer connected to live HTLC. */
i->htlc = NULL;
/* Can be NULL if JSON RPC goes away. */
if (i->cmd)
handle_json(i->cmd, htlc, f);
return;
}
}
/* Can happen with testing low-level commands. */
log_unusual(dstate->base_log, "No command for HTLC %"PRIu64" %s",
htlc->id, htlc->r ? "fulfill" : "fail");
}
/* When JSON RPC goes away, cmd is freed: detach from any running paycommand */
static void remove_cmd_from_pc(struct command *cmd)
{
struct pay_command *pc;
list_for_each(&cmd->dstate->pay_commands, pc, list) {
if (pc->cmd == cmd) {
pc->cmd = NULL;
return;
}
}
/* We can reach here, in the case where another pay command
* re-uses the pc->cmd before we get around to cleaning up. */
}
static struct pay_command *find_pay_command(struct lightningd_state *dstate,
const struct sha256 *rhash)
{
struct pay_command *pc;
list_for_each(&dstate->pay_commands, pc, list) {
if (structeq(rhash, &pc->rhash))
return pc;
}
return NULL;
}
/* For database restore. */
bool pay_add(struct lightningd_state *dstate,
const struct sha256 *rhash,
u64 msatoshi,
const struct pubkey *ids,
struct htlc *htlc,
const u8 *fail UNNEEDED,
const struct preimage *r)
{
struct pay_command *pc;
if (find_pay_command(dstate, rhash))
return false;
pc = tal(dstate, struct pay_command);
pc->rhash = *rhash;
pc->msatoshi = msatoshi;
pc->ids = tal_dup_arr(pc, struct pubkey, ids, tal_count(ids), 0);
pc->htlc = htlc;
if (r)
pc->rval = tal_dup(pc, struct preimage, r);
else
pc->rval = NULL;
pc->cmd = NULL;
list_add_tail(&dstate->pay_commands, &pc->list);
return true;
}
static void json_add_route(struct json_result *response,
const struct pubkey *id,
u64 amount, unsigned int delay)
{
json_object_start(response, NULL);
json_add_pubkey(response, "id", id);
json_add_u64(response, "msatoshi", amount);
json_add_num(response, "delay", delay);
json_object_end(response);
}
static void json_getroute(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
struct pubkey id;
jsmntok_t *idtok, *msatoshitok, *riskfactortok;
struct json_result *response;
size_t i;
u64 msatoshi;
double riskfactor;
if (!json_get_params(buffer, params,
"id", &idtok,
"msatoshi", &msatoshitok,
"riskfactor", &riskfactortok,
NULL)) {
command_fail(cmd, "Need id, msatoshi and riskfactor");
return;
}
if (!pubkey_from_hexstr(buffer + idtok->start,
idtok->end - idtok->start, &id)) {
command_fail(cmd, "Invalid id");
return;
}
if (!json_tok_u64(buffer, msatoshitok, &msatoshi)) {
command_fail(cmd, "'%.*s' is not a valid number",
(int)(msatoshitok->end - msatoshitok->start),
buffer + msatoshitok->start);
return;
}
if (!json_tok_double(buffer, riskfactortok, &riskfactor)) {
command_fail(cmd, "'%.*s' is not a valid double",
(int)(riskfactortok->end - riskfactortok->start),
buffer + riskfactortok->start);
return;
}
struct route_hop *hops = get_route(cmd, cmd->dstate->rstate, &cmd->dstate->id, &id, msatoshi, riskfactor);
if (!hops) {
command_fail(cmd, "no route found");
return;
}
response = new_json_result(cmd);
json_object_start(response, NULL);
json_array_start(response, "route");
for (i = 0; i < tal_count(hops); i++)
json_add_route(response,
&hops[i].nodeid, hops[i].amount, hops[i].delay);
json_array_end(response);
json_object_end(response);
command_success(cmd, response);
}
static const struct json_command getroute_command = {
"getroute",
json_getroute,
"Return route to {id} for {msatoshi}, using {riskfactor}",
"Returns a {route} array of {id} {msatoshi} {delay}: msatoshi and delay (in blocks) is cumulative."
};
AUTODATA(json_command, &getroute_command);
static void json_sendpay(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
struct pubkey *ids;
jsmntok_t *routetok, *rhashtok;
const jsmntok_t *t, *end;
unsigned int delay;
size_t n_hops;
struct sha256 rhash;
struct peer *peer;
struct pay_command *pc;
bool replacing = false;
const u8 *onion;
u8 sessionkey[32];
enum fail_error error_code;
const char *err;
struct hoppayload *hoppayloads;
u64 amount, lastamount;
struct onionpacket *packet;
if (!json_get_params(buffer, params,
"route", &routetok,
"rhash", &rhashtok,
NULL)) {
command_fail(cmd, "Need route and rhash");
return;
}
if (!hex_decode(buffer + rhashtok->start,
rhashtok->end - rhashtok->start,
&rhash, sizeof(rhash))) {
command_fail(cmd, "'%.*s' is not a valid sha256 hash",
(int)(rhashtok->end - rhashtok->start),
buffer + rhashtok->start);
return;
}
if (routetok->type != JSMN_ARRAY) {
command_fail(cmd, "'%.*s' is not an array",
(int)(routetok->end - routetok->start),
buffer + routetok->start);
return;
}
end = json_next(routetok);
n_hops = 0;
ids = tal_arr(cmd, struct pubkey, n_hops);
hoppayloads = tal_arr(cmd, struct hoppayload, 0);
for (t = routetok + 1; t < end; t = json_next(t)) {
const jsmntok_t *amttok, *idtok, *delaytok;
if (t->type != JSMN_OBJECT) {
command_fail(cmd, "route %zu '%.*s' is not an object",
n_hops,
(int)(t->end - t->start),
buffer + t->start);
return;
}
amttok = json_get_member(buffer, t, "msatoshi");
idtok = json_get_member(buffer, t, "id");
delaytok = json_get_member(buffer, t, "delay");
if (!amttok || !idtok || !delaytok) {
command_fail(cmd, "route %zu needs msatoshi/id/delay",
n_hops);
return;
}
if (n_hops == 0) {
/* What we will send */
if (!json_tok_u64(buffer, amttok, &amount)) {
command_fail(cmd, "route %zu invalid msatoshi", n_hops);
return;
}
lastamount = amount;
} else{
/* What that hop will forward */
tal_resize(&hoppayloads, n_hops);
memset(&hoppayloads[n_hops-1], 0, sizeof(struct hoppayload));
if (!json_tok_u64(buffer, amttok, &hoppayloads[n_hops-1].amt_to_forward)) {
command_fail(cmd, "route %zu invalid msatoshi", n_hops);
return;
}
/* FIXME: Populate outgoing_cltv_value */
lastamount = hoppayloads[n_hops-1].amt_to_forward;
}
tal_resize(&ids, n_hops+1);
memset(&ids[n_hops], 0, sizeof(ids[n_hops]));
if (!pubkey_from_hexstr(buffer + idtok->start,
idtok->end - idtok->start,
&ids[n_hops])) {
command_fail(cmd, "route %zu invalid id", n_hops);
return;
}
/* Only need first delay. */
if (n_hops == 0 && !json_tok_number(buffer, delaytok, &delay)) {
command_fail(cmd, "route %zu invalid delay", n_hops);
return;
}
n_hops++;
}
/* Add payload for final hop */
tal_resize(&hoppayloads, n_hops);
memset(&hoppayloads[n_hops-1], 0, sizeof(struct hoppayload));
if (n_hops == 0) {
command_fail(cmd, "Empty route");
return;
}
pc = find_pay_command(cmd->dstate, &rhash);
if (pc) {
replacing = true;
log_debug(cmd->dstate->base_log, "json_sendpay: found previous");
if (pc->htlc) {
log_add(cmd->dstate->base_log, "... still in progress");
command_fail(cmd, "still in progress");
return;
}
if (pc->rval) {
size_t old_nhops = tal_count(pc->ids);
log_add(cmd->dstate->base_log, "... succeeded");
/* Must match successful payment parameters. */
if (pc->msatoshi != lastamount) {
command_fail(cmd,
"already succeeded with amount %"
PRIu64, pc->msatoshi);
return;
}
if (!structeq(&pc->ids[old_nhops-1], &ids[n_hops-1])) {
char *previd;
previd = pubkey_to_hexstr(cmd,
&pc->ids[old_nhops-1]);
command_fail(cmd,
"already succeeded to %s",
previd);
return;
}
json_pay_success(cmd, pc->rval);
return;
}
log_add(cmd->dstate->base_log, "... retrying");
}
peer = find_peer(cmd->dstate, &ids[0]);
if (!peer) {
command_fail(cmd, "no connection to first peer found");
return;
}
randombytes_buf(&sessionkey, sizeof(sessionkey));
/* Onion will carry us from first peer onwards. */
packet = create_onionpacket(cmd, ids, hoppayloads, sessionkey,
rhash.u.u8, sizeof(struct sha256));
onion = serialize_onionpacket(cmd, packet);
if (pc)
pc->ids = tal_free(pc->ids);
else
pc = tal(cmd->dstate, struct pay_command);
pc->cmd = cmd;
pc->rhash = rhash;
pc->rval = NULL;
pc->ids = tal_steal(pc, ids);
pc->msatoshi = lastamount;
/* Expiry for HTLCs is absolute. And add one to give some margin. */
err = command_htlc_add(peer, amount,
delay + get_block_height(cmd->dstate->topology)
+ 1,
&rhash, NULL,
onion, &error_code, &pc->htlc);
if (err) {
command_fail(cmd, "could not add htlc: %u: %s", error_code, err);
tal_free(pc);
return;
}
if (replacing) {
if (!db_replace_pay_command(cmd->dstate, &pc->rhash,
pc->ids, pc->msatoshi,
pc->htlc)) {
command_fail(cmd, "database error");
/* We could reconnect, but db error is *bad*. */
peer_fail(peer, __func__);
tal_free(pc);
return;
}
} else {
if (!db_new_pay_command(cmd->dstate, &pc->rhash,
pc->ids, pc->msatoshi,
pc->htlc)) {
command_fail(cmd, "database error");
/* We could reconnect, but db error is *bad*. */
peer_fail(peer, __func__);
tal_free(pc);
return;
}
}
/* Wait until we get response. */
list_add_tail(&cmd->dstate->pay_commands, &pc->list);
tal_add_destructor(cmd, remove_cmd_from_pc);
}
static const struct json_command sendpay_command = {
"sendpay",
json_sendpay,
"Send along {route} in return for preimage of {rhash}",
"Returns the {preimage} on success"
};
AUTODATA(json_command, &sendpay_command);

19
daemon/pay.h

@ -1,19 +0,0 @@
#ifndef LIGHTNING_DAEMON_PAY_H
#define LIGHTNING_DAEMON_PAY_H
#include "config.h"
struct htlc;
struct lightningd_state;
struct preimage;
void complete_pay_command(struct lightningd_state *dstate,
const struct htlc *htlc);
bool pay_add(struct lightningd_state *dstate,
const struct sha256 *rhash,
u64 msatoshi,
const struct pubkey *ids,
struct htlc *htlc,
const u8 *fail,
const struct preimage *r);
#endif /* LIGHTNING_DAEMON_PAY_H */

5294
daemon/peer.c

File diff suppressed because it is too large

91
daemon/peer.h

@ -1,91 +0,0 @@
#ifndef LIGHTNING_DAEMON_PEER_H
#define LIGHTNING_DAEMON_PEER_H
#include "config.h"
#include "bitcoin/locktime.h"
#include "bitcoin/privkey.h"
#include "bitcoin/pubkey.h"
#include "bitcoin/script.h"
#include "bitcoin/shadouble.h"
#include "channel.h"
#include "failure.h"
#include "feechange.h"
#include "htlc.h"
#include "lightning.pb-c.h"
#include "netaddr.h"
#include "protobuf_convert.h"
#include "state.h"
#include "wire/gen_peer_wire.h"
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/crypto/shachain/shachain.h>
#include <ccan/list/list.h>
#include <ccan/time/time.h>
struct log;
struct lightningd_state;
struct peer;
/* Mapping for id -> network address. */
struct peer_address {
struct list_node list;
struct pubkey id;
struct netaddr addr;
};
void setup_listeners(struct lightningd_state *dstate);
void peer_debug(struct peer *peer, const char *fmt, ...)
PRINTF_FMT(2,3);
struct peer *find_peer(struct lightningd_state *dstate, const struct pubkey *id);
struct peer *find_peer_by_pkhash(struct lightningd_state *dstate, const u8 *pkhash);
struct peer *new_peer(struct lightningd_state *dstate,
struct log *log,
enum state state,
bool offer_anchor);
/* Populates very first peer->{local,remote}.commit->{tx,cstate} */
bool setup_first_commit(struct peer *peer);
/* Whenever we send a signature, remember the txid -> commit_num mapping */
void peer_add_their_commit(struct peer *peer,
const struct sha256_double *txid, u64 commit_num);
/* Allocate a new commit_info struct. */
struct commit_info *new_commit_info(const tal_t *ctx, u64 commit_num);
/* Freeing removes from map, too */
struct htlc *peer_new_htlc(struct peer *peer,
u64 id,
u64 msatoshi,
const struct sha256 *rhash,
u32 expiry,
const u8 *route,
size_t route_len,
struct htlc *src,
enum htlc_state state);
const char *command_htlc_add(struct peer *peer, u64 msatoshi,
unsigned int expiry,
const struct sha256 *rhash,
struct htlc *src,
const u8 *route,
enum fail_error *error_code,
struct htlc **htlc);
/* Peer has an issue, breakdown and fail. */
void peer_fail(struct peer *peer, const char *caller);
void peer_watch_anchor(struct peer *peer, int depth);
struct bitcoin_tx *peer_create_close_tx(const tal_t *ctx,
struct peer *peer, u64 fee);
u32 get_peer_min_block(struct lightningd_state *dstate);
void debug_dump_peers(struct lightningd_state *dstate);
void reconnect_peers(struct lightningd_state *dstate);
void rebroadcast_anchors(struct lightningd_state *dstate);
void cleanup_peers(struct lightningd_state *dstate);
#endif /* LIGHTNING_DAEMON_PEER_H */

210
daemon/peer_internal.h

@ -1,210 +0,0 @@
/* This header holds structure definitions for struct peer, which must
* not be exposed to ../lightningd/ */
#ifndef LIGHTNING_DAEMON_PEER_INTERNAL_H
#define LIGHTNING_DAEMON_PEER_INTERNAL_H
#include "config.h"
struct anchor_input {
struct sha256_double txid;
unsigned int index;
/* Amount of input (satoshis), and output (satoshis) */
u64 in_amount, out_amount;
/* Wallet entry to use to spend. */
struct pubkey walletkey;
};
/* Information we remember for their commitment txs which we signed.
*
* Given the commit_num, we can use shachain to derive the revocation preimage
* (if we've received it yet: we might have not, for the last).
*/
struct their_commit {
struct list_node list;
struct sha256_double txid;
u64 commit_num;
};
struct commit_info {
/* Commit number (0 == from open) */
u64 commit_num;
/* Revocation hash. */
struct sha256 revocation_hash;
/* Commit tx & txid */
struct bitcoin_tx *tx;
struct sha256_double txid;
/* Channel state for this tx. */
struct channel_state *cstate;
/* Other side's signature for last commit tx (if known) */
secp256k1_ecdsa_signature *sig;
/* Order which commit was sent (theirs) / revocation was sent (ours) */
s64 order;
};
struct peer_visible_state {
/* Is this side funding the channel? */
bool offer_anchor;
/* Key for commitment tx inputs, then key for commitment tx outputs */
struct pubkey commitkey, finalkey;
/* How long to they want the other's outputs locked (blocks) */
struct rel_locktime locktime;
/* Minimum depth of anchor before channel usable. */
unsigned int mindepth;
/* Commitment fee they're offering (satoshi). */
u64 commit_fee_rate;
/* Revocation hash for next commit tx. */
struct sha256 next_revocation_hash;
/* Commit txs: last one is current. */
struct commit_info *commit;
/* cstate to generate next commitment tx. */
struct channel_state *staging_cstate;
};
struct peer {
/* dstate->peers list */
struct list_node list;
/* State in state machine. */
enum state state;
/* Network connection. */
struct io_conn *conn;
/* Are we connected now? (Crypto handshake completed). */
bool connected;
/* If we're doing an open, this is the command which triggered it */
struct command *open_jsoncmd;
/* If we're doing a commit, this is the command which triggered it */
struct command *commit_jsoncmd;
/* Global state. */
struct lightningd_state *dstate;
/* Their ID. */
struct pubkey *id;
/* Order counter for transmission of revocations/commitments. */
s64 order_counter;
/* Current received packet. */
Pkt *inpkt;
/* Queue of output packets. */
Pkt **outpkt;
/* Their commitments we have signed (which could appear on chain). */
struct list_head their_commits;
/* Number of commitment signatures we've received. */
u64 their_commitsigs;
/* Anchor tx output */
struct {
struct sha256_double txid;
unsigned int index;
u64 satoshis;
u8 *witnessscript;
/* Minimum possible depth for anchor */
unsigned int min_depth;
/* If we're creating anchor, this tells us where to source it */
struct anchor_input *input;
/* If we created it, we keep entire tx. */
const struct bitcoin_tx *tx;
/* Depth to trigger anchor if still opening, or -1. */
int ok_depth;
/* Did we create anchor? */
bool ours;
} anchor;
struct {
/* Their signature for our current commit sig. */
secp256k1_ecdsa_signature theirsig;
/* The watch we have on a live commit tx. */
struct txwatch *watch;
} cur_commit;
/* Counter to make unique HTLC ids. */
u64 htlc_id_counter;
/* Mutual close info. */
struct {
/* Our last suggested closing fee. */
u64 our_fee;
/* If they've offered a signature, these are set: */
secp256k1_ecdsa_signature *their_sig;
/* If their_sig is non-NULL, this is the fee. */
u64 their_fee;
/* scriptPubKey we/they want for closing. */
u8 *our_script, *their_script;
/* Last sent (in case we need to retransmit) */
s64 shutdown_order, closing_order;
/* How many closing sigs have we receieved? */
u32 sigs_in;
} closing;
/* If we're closing on-chain */
struct {
/* Everything (watches, resolved[], etc) tal'ed off this:
* The commit which spends the anchor tx. */
const struct bitcoin_tx *tx;
struct sha256_double txid;
/* If >= 0, indicates which txout is to us and to them. */
int to_us_idx, to_them_idx;
/* Maps what txouts are HTLCs (NULL implies to_us/them_idx). */
struct htlc **htlcs;
/* Witness scripts for each output (where appropriate) */
const u8 **wscripts;
/* The tx which resolves each txout. */
const struct bitcoin_tx **resolved;
} onchain;
/* All HTLCs. */
struct htlc_map htlcs;
/* We only track one feechange per state: last one counts. */
struct feechange *feechanges[FEECHANGE_STATE_INVALID];
/* Current ongoing packetflow */
struct io_data *io_data;
/* What happened. */
struct log *log;
/* Things we're watching for (see watches.c) */
struct list_head watches;
/* Timeout for collecting changes before sending commit. */
struct oneshot *commit_timer;
/* Private keys for dealing with this peer. */
struct peer_secrets *secrets;
/* Our route connection to peer: NULL until we are in normal mode. */
struct node_connection *nc;
/* For testing. */
bool fake_close;
bool output_enabled;
/* Stuff we have in common. */
struct peer_visible_state local, remote;
/* If we have sent a new commit tx, but not received their revocation */
struct sha256 *their_prev_revocation_hash;
/* this is where we will store their revocation preimages*/
struct shachain their_preimages;
/* High water mark for the staggered broadcast */
u64 broadcast_index;
};
#endif /* LIGHTNING_DAEMON_PEER_INTERNAL_H */

169
daemon/routingrpc.c

@ -1,169 +0,0 @@
#include "jsonrpc.h"
#include "lightningd.h"
#include "log.h"
#include "routing.h"
static void json_add_route(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
jsmntok_t *srctok, *dsttok, *basetok, *vartok, *delaytok, *minblockstok;
struct pubkey src, dst;
u32 base, var, delay, minblocks;
if (!json_get_params(buffer, params,
"src", &srctok,
"dst", &dsttok,
"base", &basetok,
"var", &vartok,
"delay", &delaytok,
"minblocks", &minblockstok,
NULL)) {
command_fail(cmd, "Need src, dst, base, var, delay & minblocks");
return;
}
if (!pubkey_from_hexstr(buffer + srctok->start,
srctok->end - srctok->start, &src)) {
command_fail(cmd, "src %.*s not valid",
srctok->end - srctok->start,
buffer + srctok->start);
return;
}
if (!pubkey_from_hexstr(buffer + dsttok->start,
dsttok->end - dsttok->start, &dst)) {
command_fail(cmd, "dst %.*s not valid",
dsttok->end - dsttok->start,
buffer + dsttok->start);
return;
}
if (!json_tok_number(buffer, basetok, &base)
|| !json_tok_number(buffer, vartok, &var)
|| !json_tok_number(buffer, delaytok, &delay)
|| !json_tok_number(buffer, minblockstok, &minblocks)) {
command_fail(cmd,
"base, var, delay and minblocks must be numbers");
return;
}
add_connection(cmd->dstate->rstate, &src, &dst, base, var, delay, minblocks);
command_success(cmd, null_response(cmd));
}
static const struct json_command dev_add_route_command = {
"dev-add-route",
json_add_route,
"Add route from {src} to {dst}, {base} rate in msatoshi, {var} rate in msatoshi, {delay} blocks delay and {minblocks} minimum timeout",
"Returns an empty result on success"
};
AUTODATA(json_command, &dev_add_route_command);
static void json_getchannels(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
struct json_result *response = new_json_result(cmd);
struct node_map_iter it;
struct node *n;
struct node_map *nodes = cmd->dstate->rstate->nodes;
struct node_connection *c;
int num_conn, i;
json_object_start(response, NULL);
json_array_start(response, "channels");
for (n = node_map_first(nodes, &it); n; n = node_map_next(nodes, &it)) {
num_conn = tal_count(n->out);
for (i = 0; i < num_conn; i++){
c = n->out[i];
json_object_start(response, NULL);
json_add_pubkey(response, "from", &n->id);
json_add_pubkey(response, "to", &c->dst->id);
json_add_num(response, "base_fee", c->base_fee);
json_add_num(response, "proportional_fee", c->proportional_fee);
json_add_num(response, "expiry", c->delay);
json_add_bool(response, "active", c->active);
json_object_end(response);
}
}
json_array_end(response);
json_object_end(response);
command_success(cmd, response);
}
static const struct json_command getchannels_command = {
"getchannels",
json_getchannels,
"List all known channels.",
"Returns a 'channels' array with all known channels including their fees."
};
AUTODATA(json_command, &getchannels_command);
static void json_routefail(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
jsmntok_t *enabletok;
bool enable;
if (!json_get_params(buffer, params,
"enable", &enabletok,
NULL)) {
command_fail(cmd, "Need enable");
return;
}
if (!json_tok_bool(buffer, enabletok, &enable)) {
command_fail(cmd, "enable must be true or false");
return;
}
log_debug(cmd->dstate->base_log, "dev-routefail: routefail %s",
enable ? "enabled" : "disabled");
cmd->dstate->dev_never_routefail = !enable;
command_success(cmd, null_response(cmd));
}
static const struct json_command dev_routefail_command = {
"dev-routefail",
json_routefail,
"FAIL htlcs that we can't route if {enable}",
"Returns an empty result on success"
};
AUTODATA(json_command, &dev_routefail_command);
static void json_getnodes(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
struct json_result *response = new_json_result(cmd);
struct node *n;
struct node_map_iter i;
size_t j;
n = node_map_first(cmd->dstate->rstate->nodes, &i);
json_object_start(response, NULL);
json_array_start(response, "nodes");
while (n != NULL) {
json_object_start(response, NULL);
json_add_pubkey(response, "nodeid", &n->id);
json_array_start(response, "addresses");
for (j=0; j<tal_count(n->addresses); j++) {
json_add_address(response, NULL, &n->addresses[j]);
}
json_array_end(response);
json_object_end(response);
n = node_map_next(cmd->dstate->rstate->nodes, &i);
}
json_array_end(response);
json_object_end(response);
command_success(cmd, response);
}
static const struct json_command getnodes_command = {
"getnodes",
json_getnodes,
"List all known nodes in the network.",
"Returns a 'nodes' array"
};
AUTODATA(json_command, &getnodes_command);

251
daemon/secrets.c

@ -1,251 +0,0 @@
#include "bitcoin/privkey.h"
#include "bitcoin/shadouble.h"
#include "bitcoin/signature.h"
#include "lightningd.h"
#include "log.h"
#include "peer.h"
#include "peer_internal.h"
#include "secrets.h"
#include "utils.h"
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/crypto/shachain/shachain.h>
#include <ccan/mem/mem.h>
#include <ccan/noerr/noerr.h>
#include <ccan/read_write_all/read_write_all.h>
#include <ccan/short_types/short_types.h>
#include <ccan/tal/str/str.h>
#include <errno.h>
#include <fcntl.h>
#include <secp256k1.h>
#include <sodium/randombytes.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
void privkey_sign(struct lightningd_state *dstate, const void *src, size_t len,
secp256k1_ecdsa_signature *sig)
{
struct sha256_double h;
sha256_double(&h, memcheck(src, len), len);
sign_hash(dstate->privkey, &h, sig);
}
struct peer_secrets {
/* Two private keys, one for commit txs, one for final output. */
struct privkey commit, final;
/* Seed from which we generate revocation hashes. */
struct sha256 revocation_seed;
};
void peer_sign_theircommit(const struct peer *peer,
struct bitcoin_tx *commit,
secp256k1_ecdsa_signature *sig)
{
/* Commit tx only has one input: that of the anchor. */
sign_tx_input(commit, 0,
NULL,
peer->anchor.witnessscript,
&peer->secrets->commit,
&peer->local.commitkey,
sig);
}
void peer_sign_ourcommit(const struct peer *peer,
struct bitcoin_tx *commit,
secp256k1_ecdsa_signature *sig)
{
/* Commit tx only has one input: that of the anchor. */
sign_tx_input(commit, 0,
NULL,
peer->anchor.witnessscript,
&peer->secrets->commit,
&peer->local.commitkey,
sig);
}
void peer_sign_spend(const struct peer *peer,
struct bitcoin_tx *spend,
const u8 *commit_witnessscript,
secp256k1_ecdsa_signature *sig)
{
/* Spend tx only has one input: that of the commit tx. */
sign_tx_input(spend, 0,
NULL,
commit_witnessscript,
&peer->secrets->final,
&peer->local.finalkey,
sig);
}
void peer_sign_htlc_refund(const struct peer *peer,
struct bitcoin_tx *spend,
const u8 *htlc_witnessscript,
secp256k1_ecdsa_signature *sig)
{
/* Spend tx only has one input: that of the commit tx. */
sign_tx_input(spend, 0,
NULL,
htlc_witnessscript,
&peer->secrets->final,
&peer->local.finalkey,
sig);
}
void peer_sign_htlc_fulfill(const struct peer *peer,
struct bitcoin_tx *spend,
const u8 *htlc_witnessscript,
secp256k1_ecdsa_signature *sig)
{
/* Spend tx only has one input: that of the commit tx. */
sign_tx_input(spend, 0,
NULL,
htlc_witnessscript,
&peer->secrets->final,
&peer->local.finalkey,
sig);
}
void peer_sign_mutual_close(const struct peer *peer,
struct bitcoin_tx *close,
secp256k1_ecdsa_signature *sig)
{
sign_tx_input(close, 0,
NULL,
peer->anchor.witnessscript,
&peer->secrets->commit,
&peer->local.commitkey,
sig);
}
void peer_sign_steal_input(const struct peer *peer,
struct bitcoin_tx *spend,
size_t i,
const u8 *witnessscript,
secp256k1_ecdsa_signature *sig)
{
/* Spend tx only has one input: that of the commit tx. */
sign_tx_input(spend, i,
NULL,
witnessscript,
&peer->secrets->final,
&peer->local.finalkey,
sig);
}
static void new_keypair(struct lightningd_state *dstate,
struct privkey *privkey, struct pubkey *pubkey)
{
do {
randombytes_buf(privkey->secret.data,
sizeof(privkey->secret.data));
} while (!pubkey_from_privkey(privkey, pubkey));
}
void peer_secrets_init(struct peer *peer)
{
peer->secrets = tal(peer, struct peer_secrets);
new_keypair(peer->dstate, &peer->secrets->commit, &peer->local.commitkey);
new_keypair(peer->dstate, &peer->secrets->final, &peer->local.finalkey);
randombytes_buf(peer->secrets->revocation_seed.u.u8, sizeof(peer->secrets->revocation_seed.u.u8));
}
void peer_get_revocation_preimage(const struct peer *peer, u64 index,
struct sha256 *preimage)
{
// generate hashes in reverse order, otherwise the first hash gives away everything
shachain_from_seed(&peer->secrets->revocation_seed, 0xFFFFFFFFFFFFFFFFL - index, preimage);
}
void peer_get_revocation_hash(const struct peer *peer, u64 index,
struct sha256 *rhash)
{
struct sha256 preimage;
peer_get_revocation_preimage(peer, index, &preimage);
sha256(rhash, preimage.u.u8, sizeof(preimage.u.u8));
}
const char *peer_secrets_for_db(const tal_t *ctx, struct peer *peer)
{
const struct peer_secrets *ps = peer->secrets;
return tal_fmt(ctx, "x'%s', x'%s', x'%s'",
tal_hexstr(ctx, &ps->commit, sizeof(ps->commit)),
tal_hexstr(ctx, &ps->final, sizeof(ps->final)),
tal_hexstr(ctx, &ps->revocation_seed,
sizeof(ps->revocation_seed)));
}
void peer_set_secrets_from_db(struct peer *peer,
const void *commit_privkey,
size_t commit_privkey_len,
const void *final_privkey,
size_t final_privkey_len,
const void *revocation_seed,
size_t revocation_seed_len)
{
struct peer_secrets *ps = tal(peer, struct peer_secrets);
assert(!peer->secrets);
peer->secrets = ps;
if (commit_privkey_len != sizeof(ps->commit)
|| final_privkey_len != sizeof(ps->final)
|| revocation_seed_len != sizeof(ps->revocation_seed))
fatal("peer_set_secrets_from_db: bad lengths %zu/%zu/%zu",
commit_privkey_len, final_privkey_len,
revocation_seed_len);
memcpy(&ps->commit, commit_privkey, commit_privkey_len);
memcpy(&ps->final, final_privkey, final_privkey_len);
memcpy(&ps->revocation_seed, revocation_seed, revocation_seed_len);
if (!pubkey_from_privkey(&ps->commit, &peer->local.commitkey))
fatal("peer_set_secrets_from_db:bad commit privkey");
if (!pubkey_from_privkey(&ps->final, &peer->local.finalkey))
fatal("peer_set_secrets_from_db:bad final privkey");
}
void secrets_init(struct lightningd_state *dstate)
{
int fd;
dstate->privkey = tal(dstate, struct privkey);
fd = open("privkey", O_RDONLY);
if (fd < 0) {
if (errno != ENOENT)
fatal("Failed to open privkey: %s", strerror(errno));
log_unusual(dstate->base_log, "Creating privkey file");
new_keypair(dstate, dstate->privkey, &dstate->id);
fd = open("privkey", O_CREAT|O_EXCL|O_WRONLY, 0400);
if (fd < 0)
fatal("Failed to create privkey file: %s",
strerror(errno));
if (!write_all(fd, &dstate->privkey->secret,
sizeof(dstate->privkey->secret))) {
unlink_noerr("privkey");
fatal("Failed to write to privkey file: %s",
strerror(errno));
}
if (fsync(fd) != 0)
fatal("Failed to sync to privkey file: %s",
strerror(errno));
close(fd);
fd = open("privkey", O_RDONLY);
if (fd < 0)
fatal("Failed to reopen privkey: %s", strerror(errno));
}
if (!read_all(fd, &dstate->privkey->secret,
sizeof(dstate->privkey->secret)))
fatal("Failed to read privkey: %s", strerror(errno));
close(fd);
if (!pubkey_from_privkey(dstate->privkey, &dstate->id))
fatal("Invalid privkey");
log_info_struct(dstate->base_log, "ID: %s", struct pubkey, &dstate->id);
}

68
daemon/secrets.h

@ -1,68 +0,0 @@
#ifndef LIGHTNING_DAEMON_SECRETS_H
#define LIGHTNING_DAEMON_SECRETS_H
/* Routines to handle private keys. */
#include "config.h"
#include <ccan/short_types/short_types.h>
#include <ccan/tal/tal.h>
#include <secp256k1.h>
struct peer;
struct lightningd_state;
struct sha256;
void privkey_sign(struct lightningd_state *dstate, const void *src, size_t len,
secp256k1_ecdsa_signature *sig);
void peer_sign_theircommit(const struct peer *peer,
struct bitcoin_tx *commit,
secp256k1_ecdsa_signature *sig);
void peer_sign_ourcommit(const struct peer *peer,
struct bitcoin_tx *commit,
secp256k1_ecdsa_signature *sig);
void peer_sign_spend(const struct peer *peer,
struct bitcoin_tx *spend,
const u8 *commit_witnessscript,
secp256k1_ecdsa_signature *sig);
void peer_sign_htlc_refund(const struct peer *peer,
struct bitcoin_tx *spend,
const u8 *htlc_witnessscript,
secp256k1_ecdsa_signature *sig);
void peer_sign_htlc_fulfill(const struct peer *peer,
struct bitcoin_tx *spend,
const u8 *htlc_witnessscript,
secp256k1_ecdsa_signature *sig);
void peer_sign_mutual_close(const struct peer *peer,
struct bitcoin_tx *close,
secp256k1_ecdsa_signature *sig);
void peer_sign_steal_input(const struct peer *peer,
struct bitcoin_tx *spend,
size_t i,
const u8 *witnessscript,
secp256k1_ecdsa_signature *sig);
const char *peer_secrets_for_db(const tal_t *ctx, struct peer *peer);
void peer_set_secrets_from_db(struct peer *peer,
const void *commit_privkey,
size_t commit_privkey_len,
const void *final_privkey,
size_t final_privkey_len,
const void *revocation_seed,
size_t revocation_seed_len);
void peer_secrets_init(struct peer *peer);
void peer_get_revocation_hash(const struct peer *peer, u64 index,
struct sha256 *rhash);
void peer_get_revocation_preimage(const struct peer *peer, u64 index,
struct sha256 *preimage);
void secrets_init(struct lightningd_state *dstate);
#endif /* LIGHTNING_DAEMON_SECRETS_H */

479
daemon/sphinx.c

@ -1,479 +0,0 @@
#include "sphinx.h"
#include "utils.h"
#include <assert.h>
#include <bitcoin/address.h>
#include <ccan/crypto/ripemd160/ripemd160.h>
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/mem/mem.h>
#include <err.h>
#include <secp256k1_ecdh.h>
#include <sodium/crypto_auth_hmacsha256.h>
#include <sodium/crypto_stream_chacha20.h>
#define BLINDING_FACTOR_SIZE 32
#define SHARED_SECRET_SIZE 32
#define NUM_STREAM_BYTES ((2 * NUM_MAX_HOPS + 2) * SECURITY_PARAMETER)
#define KEY_LEN 32
struct hop_params {
u8 secret[SHARED_SECRET_SIZE];
u8 blind[BLINDING_FACTOR_SIZE];
secp256k1_pubkey ephemeralkey;
};
struct keyset {
u8 pi[KEY_LEN];
u8 mu[KEY_LEN];
u8 rho[KEY_LEN];
u8 gamma[KEY_LEN];
};
/* Small helper to append data to a buffer and update the position
* into the buffer
*/
static void write_buffer(u8 *dst, const void *src, const size_t len, int *pos)
{
memcpy(dst + *pos, src, len);
*pos += len;
}
/* Read len bytes from the source at position pos into dst and update
* the position pos accordingly.
*/
static void read_buffer(void *dst, const u8 *src, const size_t len, int *pos)
{
memcpy(dst, src + *pos, len);
*pos += len;
}
u8 *serialize_onionpacket(
const tal_t *ctx,
const struct onionpacket *m)
{
u8 *dst = tal_arr(ctx, u8, TOTAL_PACKET_SIZE);
u8 der[33];
size_t outputlen = 33;
int p = 0;
secp256k1_ec_pubkey_serialize(secp256k1_ctx,
der,
&outputlen,
&m->ephemeralkey,
SECP256K1_EC_COMPRESSED);
write_buffer(dst, &m->version, 1, &p);
write_buffer(dst, der, outputlen, &p);
write_buffer(dst, m->mac, sizeof(m->mac), &p);
write_buffer(dst, m->routinginfo, ROUTING_INFO_SIZE, &p);
write_buffer(dst, m->hoppayloads, TOTAL_HOP_PAYLOAD_SIZE, &p);
return dst;
}
struct onionpacket *parse_onionpacket(
const tal_t *ctx,
const void *src,
const size_t srclen
)
{
struct onionpacket *m;
int p = 0;
u8 rawEphemeralkey[33];
if (srclen != TOTAL_PACKET_SIZE)
return NULL;
m = talz(ctx, struct onionpacket);
read_buffer(&m->version, src, 1, &p);
if (m->version != 0x01) {
// FIXME add logging
return tal_free(m);
}
read_buffer(rawEphemeralkey, src, 33, &p);
if (secp256k1_ec_pubkey_parse(secp256k1_ctx, &m->ephemeralkey, rawEphemeralkey, 33) != 1)
return tal_free(m);
read_buffer(&m->mac, src, 20, &p);
read_buffer(&m->routinginfo, src, ROUTING_INFO_SIZE, &p);
read_buffer(&m->hoppayloads, src, TOTAL_HOP_PAYLOAD_SIZE, &p);
return m;
}
static struct hoppayload *parse_hoppayload(const tal_t *ctx, u8 *src)
{
int p = 0;
struct hoppayload *result = talz(ctx, struct hoppayload);
read_buffer(&result->realm, src, sizeof(result->realm), &p);
read_buffer(&result->amt_to_forward,
src, sizeof(result->amt_to_forward), &p);
read_buffer(&result->outgoing_cltv_value,
src, sizeof(result->outgoing_cltv_value), &p);
read_buffer(&result->unused_with_v0_version_on_header,
src, sizeof(result->unused_with_v0_version_on_header), &p);
return result;
}
static void serialize_hoppayload(u8 *dst, struct hoppayload *hp)
{
int p = 0;
write_buffer(dst, &hp->realm, sizeof(hp->realm), &p);
write_buffer(dst, &hp->amt_to_forward, sizeof(hp->amt_to_forward), &p);
write_buffer(dst, &hp->outgoing_cltv_value,
sizeof(hp->outgoing_cltv_value), &p);
write_buffer(dst, &hp->unused_with_v0_version_on_header,
sizeof(hp->unused_with_v0_version_on_header), &p);
}
static void xorbytes(uint8_t *d, const uint8_t *a, const uint8_t *b, size_t len)
{
size_t i;
for (i = 0; i < len; i++)
d[i] = a[i] ^ b[i];
}
/*
* Generate a pseudo-random byte stream of length `dstlen` from key `k` and
* store it in `dst`. `dst must be at least `dstlen` bytes long.
*/
static void generate_cipher_stream(void *dst, const u8 *k, size_t dstlen)
{
u8 nonce[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
crypto_stream_chacha20(dst, dstlen, nonce, k);
}
static bool compute_hmac(
void *dst,
const void *src,
size_t len,
const void *key,
size_t keylen)
{
crypto_auth_hmacsha256_state state;
crypto_auth_hmacsha256_init(&state, key, keylen);
crypto_auth_hmacsha256_update(&state, memcheck(src, len), len);
crypto_auth_hmacsha256_final(&state, dst);
return true;
}
static void compute_packet_hmac(const struct onionpacket *packet,
const u8 *assocdata, const size_t assocdatalen,
u8 *mukey, u8 *hmac)
{
u8 mactemp[ROUTING_INFO_SIZE + TOTAL_HOP_PAYLOAD_SIZE + assocdatalen];
u8 mac[32];
int pos = 0;
write_buffer(mactemp, packet->routinginfo, ROUTING_INFO_SIZE, &pos);
write_buffer(mactemp, packet->hoppayloads, TOTAL_HOP_PAYLOAD_SIZE, &pos);
write_buffer(mactemp, assocdata, assocdatalen, &pos);
compute_hmac(mac, mactemp, sizeof(mactemp), mukey, KEY_LEN);
memcpy(hmac, mac, 20);
}
static bool generate_key(void *k, const char *t, u8 tlen, const u8 *s)
{
return compute_hmac(k, s, KEY_LEN, t, tlen);
}
static bool generate_header_padding(
void *dst, size_t dstlen,
const size_t hopsize,
const char *keytype,
size_t keytypelen,
const u8 numhops,
struct hop_params *params
)
{
int i;
u8 cipher_stream[(NUM_MAX_HOPS + 1) * hopsize];
u8 key[KEY_LEN];
memset(dst, 0, dstlen);
for (i = 1; i < numhops; i++) {
if (!generate_key(&key, keytype, keytypelen, params[i - 1].secret))
return false;
generate_cipher_stream(cipher_stream, key, sizeof(cipher_stream));
int pos = ((NUM_MAX_HOPS - i) + 1) * hopsize;
xorbytes(dst, dst, cipher_stream + pos, sizeof(cipher_stream) - pos);
}
return true;
}
static void compute_blinding_factor(const secp256k1_pubkey *key,
const u8 sharedsecret[SHARED_SECRET_SIZE],
u8 res[BLINDING_FACTOR_SIZE])
{
struct sha256_ctx ctx;
u8 der[33];
size_t outputlen = 33;
struct sha256 temp;
secp256k1_ec_pubkey_serialize(secp256k1_ctx, der, &outputlen, key,
SECP256K1_EC_COMPRESSED);
sha256_init(&ctx);
sha256_update(&ctx, der, sizeof(der));
sha256_update(&ctx, sharedsecret, SHARED_SECRET_SIZE);
sha256_done(&ctx, &temp);
memcpy(res, &temp, 32);
}
static bool blind_group_element(
secp256k1_pubkey *blindedelement,
const secp256k1_pubkey *pubkey,
const u8 blind[BLINDING_FACTOR_SIZE])
{
/* tweak_mul is inplace so copy first. */
if (pubkey != blindedelement)
*blindedelement = *pubkey;
if (secp256k1_ec_pubkey_tweak_mul(secp256k1_ctx, blindedelement, blind) != 1)
return false;
return true;
}
static bool create_shared_secret(
u8 *secret,
const secp256k1_pubkey *pubkey,
const u8 *sessionkey)
{
if (secp256k1_ecdh(secp256k1_ctx, secret, pubkey, sessionkey) != 1)
return false;
return true;
}
bool onion_shared_secret(
u8 *secret,
const struct onionpacket *packet,
const struct privkey *privkey)
{
return create_shared_secret(secret, &packet->ephemeralkey,
privkey->secret.data);
}
static void generate_key_set(const u8 secret[SHARED_SECRET_SIZE],
struct keyset *keys)
{
generate_key(keys->rho, "rho", 3, secret);
generate_key(keys->pi, "pi", 2, secret);
generate_key(keys->mu, "mu", 2, secret);
generate_key(keys->gamma, "gamma", 5, secret);
}
static struct hop_params *generate_hop_params(
const tal_t *ctx,
const u8 *sessionkey,
struct pubkey path[])
{
int i, j, num_hops = tal_count(path);
secp256k1_pubkey temp;
u8 blind[BLINDING_FACTOR_SIZE];
struct hop_params *params = tal_arr(ctx, struct hop_params, num_hops);
/* Initialize the first hop with the raw information */
if (secp256k1_ec_pubkey_create(
secp256k1_ctx, &params[0].ephemeralkey, sessionkey) != 1)
return NULL;
if (!create_shared_secret(
params[0].secret, &path[0].pubkey, sessionkey))
return NULL;
compute_blinding_factor(
&params[0].ephemeralkey, params[0].secret,
params[0].blind);
/* Recursively compute all following ephemeral public keys,
* secrets and blinding factors
*/
for (i = 1; i < num_hops; i++) {
if (!blind_group_element(
&params[i].ephemeralkey,
&params[i - 1].ephemeralkey,
params[i - 1].blind))
return NULL;
/* Blind this hop's point with all previous blinding factors
* Order is indifferent, multiplication is commutative.
*/
memcpy(&blind, sessionkey, 32);
temp = path[i].pubkey;
if (!blind_group_element(&temp, &temp, blind))
return NULL;
for (j = 0; j < i; j++)
if (!blind_group_element(
&temp,
&temp,
params[j].blind))
return NULL;
/* Now hash temp and store it. This requires us to
* DER-serialize first and then skip the sign byte.
*/
u8 der[33];
size_t outputlen = 33;
secp256k1_ec_pubkey_serialize(
secp256k1_ctx, der, &outputlen, &temp,
SECP256K1_EC_COMPRESSED);
struct sha256 h;
sha256(&h, der, sizeof(der));
memcpy(&params[i].secret, &h, sizeof(h));
compute_blinding_factor(
&params[i].ephemeralkey,
params[i].secret, params[i].blind);
}
return params;
}
struct onionpacket *create_onionpacket(
const tal_t *ctx,
struct pubkey *path,
struct hoppayload hoppayloads[],
const u8 *sessionkey,
const u8 *assocdata,
const size_t assocdatalen
)
{
struct onionpacket *packet = talz(ctx, struct onionpacket);
int i, num_hops = tal_count(path);
u8 filler[2 * (num_hops - 1) * SECURITY_PARAMETER];
u8 hopfiller[(num_hops - 1) * HOP_PAYLOAD_SIZE];
struct keyset keys;
struct bitcoin_address nextaddr;
u8 nexthmac[SECURITY_PARAMETER];
u8 stream[ROUTING_INFO_SIZE], hopstream[TOTAL_HOP_PAYLOAD_SIZE];
struct hop_params *params = generate_hop_params(ctx, sessionkey, path);
u8 binhoppayloads[tal_count(path)][HOP_PAYLOAD_SIZE];
for (i = 0; i < num_hops; i++)
serialize_hoppayload(binhoppayloads[i], &hoppayloads[i]);
if (!params)
return NULL;
packet->version = 1;
memset(&nextaddr, 0, 20);
memset(nexthmac, 0, 20);
memset(packet->routinginfo, 0, ROUTING_INFO_SIZE);
generate_header_padding(filler, sizeof(filler), 2 * SECURITY_PARAMETER,
"rho", 3, num_hops, params);
generate_header_padding(hopfiller, sizeof(hopfiller), HOP_PAYLOAD_SIZE,
"gamma", 5, num_hops, params);
for (i = num_hops - 1; i >= 0; i--) {
generate_key_set(params[i].secret, &keys);
generate_cipher_stream(stream, keys.rho, ROUTING_INFO_SIZE);
/* Rightshift mix-header by 2*SECURITY_PARAMETER */
memmove(packet->routinginfo + 2 * SECURITY_PARAMETER, packet->routinginfo,
ROUTING_INFO_SIZE - 2 * SECURITY_PARAMETER);
memcpy(packet->routinginfo, &nextaddr, SECURITY_PARAMETER);
memcpy(packet->routinginfo + SECURITY_PARAMETER, nexthmac, SECURITY_PARAMETER);
xorbytes(packet->routinginfo, packet->routinginfo, stream, ROUTING_INFO_SIZE);
/* Rightshift hop-payloads and obfuscate */
memmove(packet->hoppayloads + HOP_PAYLOAD_SIZE, packet->hoppayloads,
TOTAL_HOP_PAYLOAD_SIZE - HOP_PAYLOAD_SIZE);
memcpy(packet->hoppayloads, binhoppayloads[i], HOP_PAYLOAD_SIZE);
generate_cipher_stream(hopstream, keys.gamma, TOTAL_HOP_PAYLOAD_SIZE);
xorbytes(packet->hoppayloads, packet->hoppayloads, hopstream,
TOTAL_HOP_PAYLOAD_SIZE);
if (i == num_hops - 1) {
size_t len = (NUM_MAX_HOPS - num_hops + 1) * 2 * SECURITY_PARAMETER;
memcpy(packet->routinginfo + len, filler, sizeof(filler));
len = (NUM_MAX_HOPS - num_hops + 1) * HOP_PAYLOAD_SIZE;
memcpy(packet->hoppayloads + len, hopfiller, sizeof(hopfiller));
}
compute_packet_hmac(packet, assocdata, assocdatalen, keys.mu,
nexthmac);
pubkey_to_hash160(&path[i], &nextaddr.addr);
}
memcpy(packet->mac, nexthmac, sizeof(nexthmac));
memcpy(&packet->ephemeralkey, &params[0].ephemeralkey, sizeof(secp256k1_pubkey));
return packet;
}
/*
* Given a onionpacket msg extract the information for the current
* node and unwrap the remainder so that the node can forward it.
*/
struct route_step *process_onionpacket(
const tal_t *ctx,
const struct onionpacket *msg,
const u8 *shared_secret,
const u8 *assocdata,
const size_t assocdatalen
)
{
struct route_step *step = talz(ctx, struct route_step);
u8 hmac[20];
struct keyset keys;
u8 paddedhoppayloads[TOTAL_HOP_PAYLOAD_SIZE + HOP_PAYLOAD_SIZE];
u8 hopstream[TOTAL_HOP_PAYLOAD_SIZE + HOP_PAYLOAD_SIZE];
u8 blind[BLINDING_FACTOR_SIZE];
u8 stream[NUM_STREAM_BYTES];
u8 paddedheader[ROUTING_INFO_SIZE + 2 * SECURITY_PARAMETER];
step->next = talz(step, struct onionpacket);
step->next->version = msg->version;
generate_key_set(shared_secret, &keys);
compute_packet_hmac(msg, assocdata, assocdatalen, keys.mu, hmac);
if (memcmp(msg->mac, hmac, sizeof(hmac)) != 0) {
warnx("Computed MAC does not match expected MAC, the message was modified.");
return tal_free(step);
}
//FIXME:store seen secrets to avoid replay attacks
generate_cipher_stream(stream, keys.rho, sizeof(stream));
memset(paddedheader, 0, sizeof(paddedheader));
memcpy(paddedheader, msg->routinginfo, ROUTING_INFO_SIZE);
xorbytes(paddedheader, paddedheader, stream, sizeof(stream));
/* Extract the per-hop payload */
generate_cipher_stream(hopstream, keys.gamma, sizeof(hopstream));
memset(paddedhoppayloads, 0, sizeof(paddedhoppayloads));
memcpy(paddedhoppayloads, msg->hoppayloads, TOTAL_HOP_PAYLOAD_SIZE);
xorbytes(paddedhoppayloads, paddedhoppayloads, hopstream, sizeof(hopstream));
step->hoppayload = parse_hoppayload(step, paddedhoppayloads);
memcpy(&step->next->hoppayloads, paddedhoppayloads + HOP_PAYLOAD_SIZE,
TOTAL_HOP_PAYLOAD_SIZE);
compute_blinding_factor(&msg->ephemeralkey, shared_secret, blind);
if (!blind_group_element(&step->next->ephemeralkey, &msg->ephemeralkey, blind))
return tal_free(step);
memcpy(&step->next->nexthop, paddedheader, SECURITY_PARAMETER);
memcpy(&step->next->mac,
paddedheader + SECURITY_PARAMETER,
SECURITY_PARAMETER);
memcpy(&step->next->routinginfo, paddedheader + 2 * SECURITY_PARAMETER, ROUTING_INFO_SIZE);
if (memeqzero(step->next->mac, sizeof(step->next->mac))) {
step->nextcase = ONION_END;
} else {
step->nextcase = ONION_FORWARD;
}
return step;
}

136
daemon/sphinx.h

@ -1,136 +0,0 @@
#ifndef LIGHTNING_DAEMON_SPHINX_H
#define LIGHTNING_DAEMON_SPHINX_H
#include "config.h"
#include "bitcoin/privkey.h"
#include "bitcoin/pubkey.h"
#include <ccan/short_types/short_types.h>
#include <ccan/tal/tal.h>
#include <secp256k1.h>
#include <sodium/randombytes.h>
#define SECURITY_PARAMETER 20
#define NUM_MAX_HOPS 20
#define HOP_PAYLOAD_SIZE 20
#define TOTAL_HOP_PAYLOAD_SIZE (NUM_MAX_HOPS * HOP_PAYLOAD_SIZE)
#define ROUTING_INFO_SIZE (2 * NUM_MAX_HOPS * SECURITY_PARAMETER)
#define TOTAL_PACKET_SIZE (1 + 33 + SECURITY_PARAMETER + ROUTING_INFO_SIZE + \
TOTAL_HOP_PAYLOAD_SIZE)
struct onionpacket {
/* Cleartext information */
u8 version;
u8 nexthop[20];
u8 mac[20];
secp256k1_pubkey ephemeralkey;
/* Encrypted information */
u8 routinginfo[ROUTING_INFO_SIZE];
u8 hoppayloads[TOTAL_HOP_PAYLOAD_SIZE];
};
enum route_next_case {
ONION_END = 0,
ONION_FORWARD = 1,
};
/* FIXME-OLD #4:
*
* The format of the per-hop-payload for a version 0 packet is as follows:
```
+----------------+--------------------------+-------------------------------+--------------------------------------------+
| realm (1 byte) | amt_to_forward (8 bytes) | outgoing_cltv_value (4 bytes) | unused_with_v0_version_on_header (7 bytes) |
+----------------+--------------------------+-------------------------------+--------------------------------------------+
```
*/
struct hoppayload {
u8 realm;
u64 amt_to_forward;
u32 outgoing_cltv_value;
u8 unused_with_v0_version_on_header[7];
};
struct route_step {
enum route_next_case nextcase;
struct onionpacket *next;
struct hoppayload *hoppayload;
};
/**
* create_onionpacket - Create a new onionpacket that can be routed
* over a path of intermediate nodes.
*
* @ctx: tal context to allocate from
* @path: public keys of nodes along the path.
* @hoppayloads: payloads destined for individual hosts (limited to
* HOP_PAYLOAD_SIZE bytes)
* @num_hops: path length in nodes
* @sessionkey: 20 byte random session key to derive secrets from
* @assocdata: associated data to commit to in HMACs
* @assocdatalen: length of the assocdata
*/
struct onionpacket *create_onionpacket(
const tal_t * ctx,
struct pubkey path[],
struct hoppayload hoppayloads[],
const u8 * sessionkey,
const u8 *assocdata,
const size_t assocdatalen
);
/**
* onion_shared_secret - calculate ECDH shared secret between nodes.
*
* @secret: the shared secret (32 bytes long)
* @pubkey: the public key of the other node
* @privkey: the private key of this node (32 bytes long)
*/
bool onion_shared_secret(
u8 *secret,
const struct onionpacket *packet,
const struct privkey *privkey);
/**
* process_onionpacket - process an incoming packet by stripping one
* onion layer and return the packet for the next hop.
*
* @ctx: tal context to allocate from
* @packet: incoming packet being processed
* @shared_secret: the result of onion_shared_secret.
* @hoppayload: the per-hop payload destined for the processing node.
* @assocdata: associated data to commit to in HMACs
* @assocdatalen: length of the assocdata
*/
struct route_step *process_onionpacket(
const tal_t * ctx,
const struct onionpacket *packet,
const u8 *shared_secret,
const u8 *assocdata,
const size_t assocdatalen
);
/**
* serialize_onionpacket - Serialize an onionpacket to a buffer.
*
* @ctx: tal context to allocate from
* @packet: the packet to serialize
*/
u8 *serialize_onionpacket(
const tal_t *ctx,
const struct onionpacket *packet);
/**
* parese_onionpacket - Parse an onionpacket from a buffer.
*
* @ctx: tal context to allocate from
* @src: buffer to read the packet from
* @srclen: length of the @src
*/
struct onionpacket *parse_onionpacket(
const tal_t *ctx,
const void *src,
const size_t srclen
);
#endif /* LIGHTNING_DAEMON_SPHINX_H */

77
daemon/state.h

@ -1,77 +0,0 @@
#ifndef LIGHTNING_DAEMON_STATE_H
#define LIGHTNING_DAEMON_STATE_H
#include "config.h"
#include "daemon/state_types.h"
#include <stdbool.h>
static inline bool state_is_error(enum state s)
{
return s >= STATE_ERR_BREAKDOWN && s <= STATE_ERR_INTERNAL;
}
static inline bool state_is_shutdown(enum state s)
{
return s == STATE_SHUTDOWN || s == STATE_SHUTDOWN_COMMITTING;
}
static inline bool state_is_onchain(enum state s)
{
return s >= STATE_CLOSE_ONCHAIN_CHEATED
&& s <= STATE_CLOSE_ONCHAIN_MUTUAL;
}
static inline bool state_is_normal(enum state s)
{
return s == STATE_NORMAL || s == STATE_NORMAL_COMMITTING;
}
static inline bool state_is_waiting_for_anchor(enum state s)
{
return s == STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE
|| s == STATE_OPEN_WAIT_ANCHORDEPTH;
}
static inline bool state_is_openwait(enum state s)
{
return s == STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE
|| s == STATE_OPEN_WAIT_ANCHORDEPTH
|| s == STATE_OPEN_WAIT_THEIRCOMPLETE;
}
static inline bool state_is_opening(enum state s)
{
return s <= STATE_OPEN_WAIT_THEIRCOMPLETE;
}
static inline bool state_can_io(enum state s)
{
if (state_is_error(s))
return false;
if (s == STATE_CLOSED)
return false;
if (state_is_onchain(s))
return false;
return true;
}
static inline bool state_can_commit(enum state s)
{
return s == STATE_NORMAL || s == STATE_SHUTDOWN;
}
/* FIXME-OLD #2:
*
* A node MUST NOT send a `update_add_htlc` after a `close_shutdown`
*/
static inline bool state_can_add_htlc(enum state s)
{
return state_is_normal(s);
}
static inline bool state_can_remove_htlc(enum state s)
{
return state_is_normal(s) || state_is_shutdown(s);
}
#endif /* LIGHTNING_STATE_H */

99
daemon/state_types.h

@ -1,99 +0,0 @@
#ifndef LIGHTNING_STATE_TYPES_H
#define LIGHTNING_STATE_TYPES_H
#include "config.h"
/* FIXME: cdump is really dumb, so we put these in their own header. */
#include "lightning.pb-c.h"
enum state {
STATE_INIT,
/*
* Opening.
*/
STATE_OPEN_WAIT_FOR_OPENPKT,
STATE_OPEN_WAIT_FOR_ANCHORPKT,
STATE_OPEN_WAIT_FOR_COMMIT_SIGPKT,
/* We're waiting for depth+their complete. */
STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE,
/* Got their pkt_complete. */
STATE_OPEN_WAIT_ANCHORDEPTH,
/* Got anchor depth. */
STATE_OPEN_WAIT_THEIRCOMPLETE,
/*
* Normal state.
*/
STATE_NORMAL,
STATE_NORMAL_COMMITTING,
/*
* Closing (handled outside state machine).
*/
STATE_SHUTDOWN,
STATE_SHUTDOWN_COMMITTING,
STATE_MUTUAL_CLOSING,
/* Four states to represent closing onchain (for getpeers) */
STATE_CLOSE_ONCHAIN_CHEATED,
STATE_CLOSE_ONCHAIN_THEIR_UNILATERAL,
STATE_CLOSE_ONCHAIN_OUR_UNILATERAL,
STATE_CLOSE_ONCHAIN_MUTUAL,
/* All closed. */
STATE_CLOSED,
/*
* Where angels fear to tread.
*/
/* Bad packet from them / protocol breakdown. */
STATE_ERR_BREAKDOWN,
/* The anchor didn't reach blockchain in reasonable time. */
STATE_ERR_ANCHOR_TIMEOUT,
/* We saw a tx we didn't sign. */
STATE_ERR_INFORMATION_LEAK,
/* We ended up in an unexpected state. */
STATE_ERR_INTERNAL,
STATE_MAX
};
enum state_input {
/*
* Packet inputs.
*/
PKT_OPEN = PKT__PKT_OPEN,
PKT_OPEN_ANCHOR = PKT__PKT_OPEN_ANCHOR,
PKT_OPEN_COMMIT_SIG = PKT__PKT_OPEN_COMMIT_SIG,
PKT_OPEN_COMPLETE = PKT__PKT_OPEN_COMPLETE,
/* Updating the commit transaction: new HTLC */
PKT_UPDATE_ADD_HTLC = PKT__PKT_UPDATE_ADD_HTLC,
/* Updating the commit transaction: I have your R value! */
PKT_UPDATE_FULFILL_HTLC = PKT__PKT_UPDATE_FULFILL_HTLC,
/* Updating the commit transaction: your HTLC failed upstream */
PKT_UPDATE_FAIL_HTLC = PKT__PKT_UPDATE_FAIL_HTLC,
/* Committing updates */
PKT_UPDATE_COMMIT = PKT__PKT_UPDATE_COMMIT,
PKT_UPDATE_REVOCATION = PKT__PKT_UPDATE_REVOCATION,
/* If they want to close. */
PKT_CLOSE_SHUTDOWN = PKT__PKT_CLOSE_SHUTDOWN,
/* Something unexpected went wrong. */
PKT_ERROR = PKT__PKT_ERROR,
/*
* Non-packet inputs.
*/
INPUT_NONE,
/*
* Timeouts.
*/
INPUT_CLOSE_COMPLETE_TIMEOUT,
INPUT_MAX
};
#endif /* LIGHTNING_STATE_TYPES_H */

73
daemon/test/Makefile

@ -1,73 +0,0 @@
check: daemon-tests
# We run three different bitcoinds, for different types of tests.
# Provides limited paralellism.
daemon-test-0-%:
NO_VALGRIND=$(NO_VALGRIND) VARIANT=0 daemon/test/test-$*
daemon-test-1-%:
NO_VALGRIND=$(NO_VALGRIND) VARIANT=1 daemon/test/test-$*
daemon-test-2-%:
NO_VALGRIND=$(NO_VALGRIND) VARIANT=2 daemon/test/test-$*
# These don't work in parallel, so chain the deps
daemon-test-0-steal: daemon-test-0-unilateral
daemon-test-0-unilateral: daemon-test-0-funding-timeout
daemon-test-0-funding-timeout: daemon-test-0-mutual-close-with-htlcs
daemon-test-0-mutual-close-with-htlcs: daemon-test-0-different-fees
daemon-test-0-different-fees: daemon-test-0-routing
daemon-test-0-routing: daemon-test-0-invoice
daemon-test-0-invoice: daemon-test-0-basic\ manual-commit
daemon-test-0-basic\ manual-commit: daemon-test-0-basic
daemon-test-0-basic: daemon-test-setup-0
daemon-test-2-steal\ --reconnect: daemon-test-2-unilateral\ --reconnect
daemon-test-2-unilateral\ --reconnect: daemon-test-2-funding-timeout\ --reconnect
daemon-test-2-funding-timeout\ --reconnect: daemon-test-2-mutual-close-with-htlcs\ --reconnect
daemon-test-2-mutual-close-with-htlcs\ --reconnect: daemon-test-2-different-fees\ --reconnect
daemon-test-2-different-fees\ --reconnect: daemon-test-2-routing\ --reconnect
daemon-test-2-routing\ --reconnect: daemon-test-2-invoice\ --reconnect
daemon-test-2-invoice\ --reconnect: daemon-test-2-basic\ manual-commit\ --reconnect
daemon-test-2-basic\ manual-commit\ --reconnect: daemon-test-2-basic\ --reconnect
daemon-test-2-basic\ --reconnect: daemon-test-setup-2
daemon-test-1-steal\ --restart: daemon-test-1-unilateral\ --restart
daemon-test-1-unilateral\ --restart: daemon-test-1-funding-timeout\ --restart
daemon-test-1-funding-timeout\ --restart: daemon-test-1-mutual-close-with-htlcs\ --restart
daemon-test-1-mutual-close-with-htlcs\ --restart: daemon-test-1-different-fees\ --restart
daemon-test-1-different-fees\ --restart: daemon-test-1-routing\ --restart
daemon-test-1-routing\ --restart: daemon-test-1-invoice\ --restart
daemon-test-1-invoice\ --restart: daemon-test-1-basic\ manual-commit\ --restart
daemon-test-1-basic\ manual-commit\ --restart: daemon-test-1-basic\ --restart
daemon-test-1-basic\ --restart: daemon-test-setup-1
# We shutdown first in case something is left over.
daemon-test-setup-%: daemon-all
VARIANT=$* daemon/test/scripts/shutdown.sh 2>/dev/null || true
VARIANT=$* daemon/test/scripts/setup.sh
daemon-test-shutdown-0: daemon-test-0-steal
VARIANT=0 daemon/test/scripts/shutdown.sh
daemon-test-shutdown-1: daemon-test-1-steal\ --restart
VARIANT=1 daemon/test/scripts/shutdown.sh
daemon-test-shutdown-2: daemon-test-2-steal\ --reconnect
VARIANT=2 daemon/test/scripts/shutdown.sh
# Forms long dependency chains.
daemon-all-test: daemon-test-shutdown-0 daemon-test-shutdown-1 daemon-test-shutdown-2
# Note that these actually #include everything they need, except ccan/ and bitcoin/.
# That allows for unit testing of statics, and special effects.
DAEMON_TEST_SRC := $(wildcard daemon/test/run-*.c)
DAEMON_TEST_OBJS := $(DAEMON_TEST_SRC:.c=.o)
DAEMON_TEST_PROGRAMS := $(DAEMON_TEST_OBJS:.o=)
update-mocks: $(DAEMON_TEST_SRC:%=update-mocks/%)
$(DAEMON_TEST_PROGRAMS): $(CCAN_OBJS) $(BITCOIN_OBJS) $(CORE_OBJS) $(CORE_TX_OBJS) $(CORE_PROTOBUF_OBJS) $(LIBBASE58_OBJS) $(WIRE_OBJS) libsecp256k1.a libsodium.a utils.o
$(DAEMON_TEST_OBJS): $(DAEMON_HEADERS) $(DAEMON_JSMN_HEADERS) $(BITCOIN_HEADERS) $(CORE_HEADERS) $(CORE_TX_HEADERS) $(GEN_HEADERS) $(DAEMON_GEN_HEADERS) $(CCAN_HEADERS) $(WIRE_HEADERS)
daemon-unit-tests: $(DAEMON_TEST_PROGRAMS:%=unittest/%)
daemon-tests: daemon-unit-tests daemon-all-test

52
daemon/test/run-maxfee.c

@ -1,52 +0,0 @@
#include "daemon/channel.c"
#include "daemon/htlc.c"
#include "daemon/htlc_state.c"
#include <assert.h>
#include <stdio.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for db_new_htlc */
void db_new_htlc(struct peer *peer UNNEEDED, const struct htlc *htlc UNNEEDED)
{ fprintf(stderr, "db_new_htlc called!\n"); abort(); }
/* Generated stub for db_update_htlc_state */
void db_update_htlc_state(struct peer *peer UNNEEDED, const struct htlc *htlc UNNEEDED,
enum htlc_state oldstate UNNEEDED)
{ fprintf(stderr, "db_update_htlc_state called!\n"); abort(); }
/* Generated stub for log_ */
void log_(struct log *log UNNEEDED, enum log_level level UNNEEDED, const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "log_ called!\n"); abort(); }
/* Generated stub for peer_debug */
void peer_debug(struct peer *peer UNNEEDED, const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "peer_debug called!\n"); abort(); }
/* Could not find declaration for tal_hexstr */
/* Could not find declaration for type_to_string_ */
/* AUTOGENERATED MOCKS END */
static void test_maxfee(size_t htlcs, u64 funds)
{
struct channel_state cstate;
uint64_t maxrate;
cstate.side[LOCAL].pay_msat = funds;
cstate.side[LOCAL].fee_msat = 0;
cstate.num_nondust = htlcs;
maxrate = approx_max_feerate(&cstate, LOCAL);
assert(fee_by_feerate(tx_bytes(htlcs), maxrate) <= funds);
}
int main(void)
{
size_t htlcs, i;
for (htlcs = 0; htlcs < 600; htlcs++) {
for (i = 0; i < 32; i++) {
test_maxfee(htlcs, i);
test_maxfee(htlcs, 1ULL << i);
test_maxfee(htlcs, (1ULL << i) - 1);
test_maxfee(htlcs, (1ULL << i) + 1);
}
}
return 0;
}

21
daemon/test/scripts/generate-block.sh

@ -1,21 +0,0 @@
#! /bin/sh
# Generate a block.
set -e
. `dirname $0`/vars.sh
INIT=$1
# Initially we need 100 blocks so coinbase matures, giving us funds.
if [ -n "$INIT" ]; then
# To activate segwit via BIP9, we need at least 432 blocks!
$CLI generate 432 > /dev/null
if $CLI getblockchaininfo | tr -s '\012\011 ' ' ' | grep -q '"segwit": { "status": "active",'; then :
else
echo "Segwit not activated after 432 blocks?" >&2
$CLI getblockchaininfo >&2
exit 1
fi
else
$CLI generate 1 > /dev/null
fi

29
daemon/test/scripts/getinput.sh

@ -1,29 +0,0 @@
#! /bin/sh
# Query bitcoind to get (first) unspent output to spend.
###
# Nobody should *EVER* write code like this. EVER!!
###
set -e
. `dirname $0`/vars.sh
NUM=1
if [ $# = 1 ]; then
NUM=$1
shift
fi
if [ $# -gt 0 ]; then
echo "Usage: getinput.sh [INPUT-INDEX]"
exit 1
fi
TXID=`$CLI listunspent | sed -n 's/^ *"txid" *: *"\([0-9a-f]*\)",$/\1/p' | tail -n +$NUM | head -n1`
OUTNUM=`$CLI listunspent | sed -n 's/^ *"vout" *: *\([0-9]*\),$/\1/p' | tail -n +$NUM | head -n1`
AMOUNT=`$CLI listunspent | sed -n 's/^ *"amount" *: *\([0-9.]*\),$/\1/p' | tail -n +$NUM | head -n1 | tr -d . | sed 's/^0*//'`
SCRIPT=`$CLI listunspent | sed -n 's/^ *"scriptPubKey" *: *"\([0-9a-f]*\)",$/\1/p' | tail -n +$NUM | head -n1`
ADDR=`$CLI listunspent | sed -n 's/^ *"address" *: *"\([0-9a-zA-Z]*\)",$/\1/p' | tail -n +$NUM | head -n1`
PRIVKEY=`$CLI dumpprivkey $ADDR`
echo $TXID/$OUTNUM/$AMOUNT/$SCRIPT/$PRIVKEY

467
daemon/test/scripts/helpers.sh

@ -1,467 +0,0 @@
#! /bin/sh
# Sourced by test script.
# Takes the number of lightningd's we're going to start (2 or 3), then args
parse_cmdline()
{
NUM_LIGHTNINGD=$1
shift
DIR1=/tmp/lightning.$$.1
DIR2=/tmp/lightning.$$.2
REDIR1="$DIR1/output"
REDIR2="$DIR2/output"
REDIRERR1="$DIR1/errors"
REDIRERR2="$DIR2/errors"
if [ $NUM_LIGHTNINGD = 3 ]; then
DIR3=/tmp/lightning.$$.3
REDIR3="$DIR3/output"
REDIRERR3="$DIR3/errors"
fi
while [ $# != 0 ]; do
case x"$1" in
x"--valgrind-vgdb")
[ -n "$NO_VALGRIND" ] || PREFIX="$PREFIX --vgdb-error=1"
REDIR1="/dev/tty"
REDIRERR1="/dev/tty"
REDIR2="/dev/tty"
REDIRERR2="/dev/tty"
if [ $NUM_LIGHTNINGD = 3 ]; then
REDIR3="/dev/tty"
REDIRERR3="/dev/tty"
fi
;;
x"--gdb1")
GDB1=1
;;
x"--gdb2")
GDB2=1
;;
x"--gdb3")
GDB3=1
if [ $NUM_LIGHTNINGD -lt 3 ]; then
echo "$1" invalid with only 2 lightning daemons >&2
exit 1
fi
;;
x"--gdb1="*)
DAEMON1_EXTRA=--dev-debugger=${1#--gdb1=}
;;
x"--gdb2="*)
DAEMON2_EXTRA=--dev-debugger=${1#--gdb2=}
;;
x"--reconnect")
RECONNECT=reconnect
;;
x"--restart")
RECONNECT=restart
;;
x"--crash")
CRASH_ON_FAIL=1
;;
x"--verbose")
VERBOSE=1
;;
*)
echo Unknown arg "$1" >&2
exit 1
esac
shift
done
if [ -n "$VERBOSE" ]; then
FGREP="fgrep"
else
FGREP="fgrep -q"
# Suppress command output.
exec >/dev/null
fi
}
failed()
{
if [ -n "$CRASH_ON_FAIL" ]; then
$LCLI1 dev-crash 2>/dev/null || true
$LCLI2 dev-crash 2>/dev/null || true
echo -n Crash results in $DIR1 and $DIR2 >&2
if [ -n "$LCLI3" ]; then
$LCLI3 dev-crash 2>/dev/null || true
echo and $DIR3 >&2
else
echo >&2
fi
fi
cat $DIR1/errors $DIR2/errors $DIR3/errors 2>/dev/null || true
exit 1
}
setup_lightning()
{
NUM_LIGHTNINGD=$1
LCLI1="../lightning-cli --lightning-dir=$DIR1"
LCLI2="../lightning-cli --lightning-dir=$DIR2"
[ $NUM_LIGHTNINGD = 2 ] || LCLI3="../lightning-cli --lightning-dir=$DIR3"
trap failed EXIT
mkdir $DIR1 $DIR2
[ $NUM_LIGHTNINGD = 2 ] || mkdir $DIR3
cat > $DIR1/config <<EOF
disable-irc
log-level=debug
bitcoind-poll=5s
deadline-blocks=5
min-htlc-expiry=6
bitcoin-datadir=$DATADIR
locktime-blocks=6
EOF
cp $DIR1/config $DIR2/config
[ $NUM_LIGHTNINGD = 2 ] || cp $DIR1/config $DIR3/config
# Find a free TCP port.
echo port=`findport 4000 $VARIANT` >> $DIR2/config
[ $NUM_LIGHTNINGD = 2 ] || echo port=`findport 4010 $VARIANT` >> $DIR3/config
}
# Use DIR REDIR REDIRERR GDBFLAG BINARY EXTRAARGS
start_one_lightningd()
{
# Need absolute path for re-exec testing.
local CMD
CMD="$(readlink -f `pwd`/../../$5) --lightning-dir=$1"
if [ -n "$4" ]; then
echo Press return once you run: gdb --args $CMD $6 >&2
read REPLY
else
CMD="$PREFIX $CMD"
$CMD $6 > $2 2> $3 &
fi
echo $CMD $6
}
start_lightningd()
{
NUM_LIGHTNINGD=$1
BINARY=${2:-daemon/lightningd}
# If bitcoind not already running, start it.
if ! $CLI getinfo >/dev/null 2>&1; then
echo Starting bitcoind...
scripts/setup.sh
SHUTDOWN_BITCOIN=scripts/shutdown.sh
else
SHUTDOWN_BITCOIN=/bin/true
fi
LIGHTNINGD1=`start_one_lightningd $DIR1 $REDIR1 $REDIRERR1 "$GDB1" $BINARY $DAEMON1_EXTRA`
LIGHTNINGD2=`start_one_lightningd $DIR2 $REDIR2 $REDIRERR2 "$GDB2" $BINARY $DAEMON2_EXTRA`
[ $NUM_LIGHTNINGD = 2 ] || LIGHTNINGD3=`start_one_lightningd $DIR3 $REDIR3 $REDIRERR3 "$GDB3" $BINARY`
if ! check "$LCLI1 getlog 2>/dev/null | $FGREP Hello"; then
echo Failed to start daemon 1 >&2
exit 1
fi
if ! check "$LCLI2 getlog 2>/dev/null | $FGREP Hello"; then
echo Failed to start daemon 2 >&2
exit 1
fi
if [ $NUM_LIGHTNINGD = 3 ] && ! check "$LCLI3 getlog 2>/dev/null | $FGREP Hello"; then
echo Failed to start daemon 3 >&2
exit 1
fi
# Version should match binary version
GETINFO_VERSION=`$LCLI1 getinfo | sed -n 's/.*"version" : "\([^"]*\)".*/\1/p'`
LCLI_VERSION=$($LCLI1 --version | head -n1)
LDAEMON_VERSION=$($LIGHTNINGD1 --version | head -n1)
if [ $GETINFO_VERSION != $LCLI_VERSION -o $GETINFO_VERSION != $LDAEMON_VERSION ]; then
echo Wrong versions: getinfo gave $GETINFO_VERSION, cli gave $LCLI_VERSION, daemon gave $LDAEMON_VERSION >&2
exit 1
fi
ID1=`get_info_field "$LCLI1" id`
ID2=`get_info_field "$LCLI2" id`
[ $NUM_LIGHTNINGD = 2 ] || ID3=`get_info_field "$LCLI3" id`
PORT2=`get_info_field "$LCLI2" port`
[ $NUM_LIGHTNINGD = 2 ] || PORT3=`get_info_field "$LCLI3" port`
}
fund_lightningd()
{
# Make a payment into a P2SH for anchor.
P2SHADDR=`$LCLI1 newaddr | sed -n 's/{ "address" : "\(.*\)" }/\1/p'`
FUND_INPUT_TXID=`$CLI sendtoaddress $P2SHADDR 0.01`
FUND_INPUT_TX=`$CLI getrawtransaction $FUND_INPUT_TXID`
# Mine it so check_tx_spend doesn't see it (breaks some tests).
$CLI generate 1
}
lcli1()
{
if [ -n "$VERBOSE" ]; then
echo $LCLI1 "$@" >&2
fi
# Make sure we output if it fails; we need to capture it otherwise.
if ! OUT=`$LCLI1 "$@"`; then
echo "$OUT"
return 1
fi
echo "$OUT"
if [ -n "$DO_RECONNECT" ]; then
case "$1" in
# Don't restart on every get* command.
get*)
;;
dev-disconnect)
;;
stop)
;;
*)
case "$RECONNECT" in
reconnect)
[ -z "$VERBOSE" ] || echo RECONNECTING >&2
$LCLI1 dev-reconnect $ID2 >/dev/null
;;
restart)
[ -z "$VERBOSE" ] || echo RESTARTING >&2
$LCLI1 -- dev-restart $LIGHTNINGD1 >/dev/null 2>&1 || true
if ! check "$LCLI1 getlog 2>/dev/null | fgrep -q Hello"; then
echo "dev-restart failed!">&2
exit 1
fi
;;
esac
# Wait for reconnect (if peer2 still there)
if [ -z "$NO_PEER2" ] && ! check "$LCLI1 getpeers | tr -s '\012\011\" ' ' ' | fgrep -q 'connected : true'"; then
echo "Failed to reconnect!">&2
exit 1
fi
if [ "$1" = "dev-newhtlc" ]; then
# It might have gotten committed, or might be forgotten.
ID=`echo "$OUT" | extract_id`
if ! htlc_exists "$LCLI1" $2 $ID; then
if [ -z "$VERBOSE" ]; then
$LCLI1 "$@" >/dev/null 2>&1 || true
else
echo "Rerunning $LCLI1 $@" >&2
$LCLI1 "$@" >&2 || true
fi
fi
# Make sure it's confirmed before we run next command,
# in case *that* restarts (unless manual commit)
[ -n "$MANUALCOMMIT" ] || check ! htlc_is_state \'"$LCLI1"\' $2 $ID SENT_ADD_HTLC
# Removals may also be forgotten.
elif [ "$1" = "fulfillhtlc" -o "$1" = "failhtlc" ]; then
ID="$3"
if htlc_is_state "$LCLI1" $2 $ID RCVD_ADD_ACK_REVOCATION; then
if [ -z "$VERBOSE" ]; then
$LCLI1 "$@" >/dev/null 2>&1 || true
else
echo "Rerunning $LCLI1 $@" >&2
$LCLI1 "$@" >&2 || true
fi
# Make sure it's confirmed before we run next command,
# in case *that* restarts.
[ -n "$MANUALCOMMIT" ] || check ! htlc_is_state \'"$LCLI1"\' $2 $ID SENT_REMOVE_HTLC
fi
fi
;;
esac
fi
}
lcli2()
{
if [ -n "$VERBOSE" ]; then
echo $LCLI2 "$@" >&2
fi
$LCLI2 "$@"
}
lcli3()
{
if [ -n "$VERBOSE" ]; then
echo $LCLI3 "$@" >&2
fi
$LCLI3 "$@"
}
all_ok()
{
# Look for valgrind errors.
if grep ^== $DIR1/errors; then exit 1; fi
if grep ^== $DIR2/errors; then exit 1; fi
[ $NUM_LIGHTNINGD = 2 ] || if grep ^== $DIR3/errors; then exit 1; fi
# Look for unknown logging types.
if grep "UNKNOWN TYPE" $DIR1/output >&2; then exit 1; fi
if grep "UNKNOWN TYPE" $DIR2/output >&2; then exit 1; fi
[ $NUM_LIGHTNINGD = 2 ] || if grep "UNKNOWN TYPE" $DIR3/output >&2; then exit 1; fi
$SHUTDOWN_BITCOIN
trap "rm -rf $DIR1 $DIR2 $DIR3" EXIT
exit 0
}
# If result is in quotes, those are stripped. Spaces in quotes not handled
get_field()
{
tr -s '\012\011" ' ' ' | sed 's/.* '$1' : \([^, }]*\).*/\1/'
}
# If result is in quotes, those are stripped. Spaces in quotes not handled
get_info_field()
{
$1 getinfo | tr -s '\012\011" ' ' ' | sed 's/.* '$2' : \([^, }]*\).*/\1/'
}
# Peer $1 -> $2's htlc $3 is in state $4
htlc_is_state()
{
if [ $# != 4 ]; then echo "htlc_is_state got $# ARGS: $@" >&2; exit 1; fi
$1 gethtlcs $2 true | tr -s '\012\011\" ' ' ' | $FGREP "id : $3, state : $4 ," >&2
}
# Peer $1 -> $2's htlc $3 exists
htlc_exists()
{
$1 gethtlcs $2 true | tr -s '\012\011\" ' ' ' | $FGREP "id : $3," >&2
}
blockheight()
{
$CLI getblockcount
}
# Usage: <cmd to test>...
check()
{
local i=0
while ! eval "$@"; do
sleep 1
i=$(($i + 1))
if [ $i = 60 ]; then
return 1
fi
done
}
check_balance_single()
{
lcli="$1"
us_pay=$2
us_fee=$3
them_pay=$4
them_fee=$5
if check "$lcli getpeers | tr -s '\012\011\" ' ' ' | $FGREP \"our_amount : $us_pay, our_fee : $us_fee, their_amount : $them_pay, their_fee : $them_fee,\""; then :; else
echo Cannot find $lcli output: "our_amount : $us_pay, our_fee : $us_fee, their_amount : $them_pay, their_fee : $them_fee," >&2
$lcli getpeers | tr -s '\012\011" ' ' ' >&2
return 1
fi
}
check_status_single()
{
lcli="$1"
us_pay=$2
us_fee=$3
us_htlcs="$4"
them_pay=$5
them_fee=$6
them_htlcs="$7"
check_balance_single "$lcli" $us_pay $us_fee $them_pay $them_fee
if check "$lcli getpeers | tr -s '\012\011\" ' ' ' | $FGREP \"our_htlcs : [ $us_htlcs], their_htlcs : [ $them_htlcs]\""; then :; else
echo Cannot find $lcli output: "our_htlcs : [ $us_htlcs], their_htlcs : [ $them_htlcs]" >&2
$lcli getpeers | tr -s '\012\011" ' ' ' >&2
return 1
fi
}
# SEND_ -> RCVD_ and RCVD_ -> SEND_
swap_status()
{
echo "$@" | sed -e 's/state : RCVD_/@@/g' -e 's/state : SENT_/state : RCVD_/g' -e 's/@@/state : SENT_/g'
}
check_status()
{
us_pay=$1
us_fee=$2
us_htlcs="$3"
them_pay=$4
them_fee=$5
them_htlcs="$6"
check_status_single lcli1 "$us_pay" "$us_fee" "$us_htlcs" "$them_pay" "$them_fee" "$them_htlcs"
check_status_single lcli2 "$them_pay" "$them_fee" "`swap_status \"$them_htlcs\"`" "$us_pay" "$us_fee" "`swap_status \"$us_htlcs\"`"
}
check_tx_spend()
{
local FAIL
FAIL=0
if [ $# = 1 ]; then
check "$CLI getrawmempool | $FGREP $1" || FAIL=1
else
check "$CLI getrawmempool | $FGREP '\"'" || FAIL=1
fi
if [ $FAIL = 1 ]; then
echo "No tx $1 in mempool:" >&2
$CLI getrawmempool >&2
exit 1
fi
}
check_peerstate()
{
if check "$1 getpeers | $FGREP -w $2"; then :
else
echo "$1" not in state "$2": >&2
$1 getpeers >&2
exit 1
fi
}
check_peerconnected()
{
if check "$1 getpeers | tr -s '\012\011\" ' ' ' | $FGREP -w 'connected : '$2"; then :
else
echo "$1" not connected "$2": >&2
$1 getpeers >&2
exit 1
fi
}
check_no_peers()
{
if check "$1 getpeers | tr -s '\012\011\" ' ' ' | $FGREP 'peers : [ ]'"; then :
else
echo "$1" still has peers: >&2
$1 getpeers >&2
exit 1
fi
}
extract_id()
{
XID=`tr -s '\012\011\" ' ' ' | sed -n 's/{ id : \([0-9]*\) }/\1/p'`
case "$XID" in
[0-9]*)
echo $XID;;
*)
return 1;;
esac
}

47
daemon/test/scripts/setup.sh

@ -1,47 +0,0 @@
#! /bin/sh -e
. `dirname $0`/vars.sh
VERSION=$(`dirname $0`/../../lightning-cli --version | head -n1)
[ $VERSION = `git describe --always --dirty` ] || (echo Wrong version $VERSION >&2; exit 1)
# Start clean
rm -rf $DATADIR
mkdir $DATADIR
# Find a free port (racy, but hey)
PORT=`findport 18332 $VARIANT`
RPCPORT=`findport $(($PORT + 1))`
# Create appropriate config file so cmdline matches.
cat > $DATADIR/bitcoin.conf <<EOF
regtest=1
testnet=0
rpcport=$RPCPORT
port=$PORT
EOF
$DAEMON &
i=0
while ! $CLI getinfo >/dev/null 2>&1; do
if [ $i -gt 60 ]; then
echo $DAEMON start failed? >&1
exit 1
fi
sleep 1
i=$(($i + 1))
done
# Make sure they have segwit support!
if $CLI getblockchaininfo | grep -q '"segwit"'; then :
else
echo This bitcoind does not have segwit support. >&2
echo Please install a recent one >&2
exit 1
fi
`dirname $0`/generate-block.sh init
A1=$($CLI getnewaddress)
TX=`$CLI sendmany "" "{ \"$A1\":0.01 }"`
`dirname $0`/generate-block.sh

11
daemon/test/scripts/shutdown.sh

@ -1,11 +0,0 @@
#! /bin/sh -e
. `dirname $0`/vars.sh
[ ! -f $DATADIR/regtest/bitcoind.pid ] || BITCOIN_PID=`cat $DATADIR/regtest/bitcoind.pid`
$CLI stop
sleep 1 # Make sure socket is closed.
# Now make sure it's dead.
if [ -n "$BITCOIN_PID" ]; then kill -9 $BITCOIN_PID 2>/dev/null || true; fi

40
daemon/test/scripts/vars.sh

@ -1,40 +0,0 @@
# Sourced by other scripts
# Bash variables for in-depth debugging.
#set -vx
#export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
# Suppress sync if we can, for speedup.
if which eatmydata >/dev/null; then EATMYDATA=eatmydata; fi
DATADIR=/tmp/bitcoin-lightning$VARIANT
CLI="bitcoin-cli -datadir=$DATADIR"
REGTESTDIR=regtest
DAEMON="$EATMYDATA bitcoind -datadir=$DATADIR"
PREFIX=$EATMYDATA
# Always use valgrind if available (unless NO_VALGRIND=1 set)
if which valgrind >/dev/null; then :; else NO_VALGRIND=1; fi
[ -n "$NO_VALGRIND" ] || PREFIX="$EATMYDATA valgrind -q $VG_TRACE_CHILDREN --trace-children-skip=*bitcoin-cli* --error-exitcode=7"
# We inject 0.01 bitcoin, but then fees (estimatefee fails and we use a
# fee rate as per the default).
AMOUNT=991880000
# Default fee rate per kb.
FEE_RATE=200000
# Fee in millisatoshi if we have no htlcs (note rounding to make it even)
NO_HTLCS_FEE=$((338 * $FEE_RATE / 2000 * 2000))
ONE_HTLCS_FEE=$(( (338 + 32) * $FEE_RATE / 2000 * 2000))
EXTRA_FEE=$(($ONE_HTLCS_FEE - $NO_HTLCS_FEE))
findport()
{
PORT=$1
# Give two ports per variant.
if [ x"$2" != x ]; then PORT=$(($PORT + $2 * 2)); fi
while netstat -ntl | grep -q ":$PORT "; do PORT=$(($PORT + 1)); done
echo $PORT
}

359
daemon/test/test-basic

@ -1,359 +0,0 @@
#! /bin/sh -e
# Wherever we are, we want to be in daemon/test dir.
cd `git rev-parse --show-toplevel`/daemon/test
. scripts/vars.sh
. scripts/helpers.sh
if [ x"$1" = x"manual-commit" ]; then
MANUALCOMMIT=1
shift
fi
parse_cmdline 2 "$@"
setup_lightning 2
if [ -n "$MANUALCOMMIT" ]; then
# Aka. never.
echo 'commit-time=1h' >> $DIR1/config
echo 'commit-time=1h' >> $DIR2/config
fi
start_lightningd 2
fund_lightningd
# Check IDs match logs
[ `$LCLI1 getlog | sed -n 's/.*"ID: \([0-9a-f]*\)".*/\1/p'` = $ID1 ]
[ `$LCLI2 getlog | sed -n 's/.*"ID: \([0-9a-f]*\)".*/\1/p'` = $ID2 ]
lcli1 connect localhost $PORT2 $FUND_INPUT_TX &
# Expect them to be waiting for anchor, and ack from other side.
check_peerstate lcli1 STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE
check_peerstate lcli2 STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE
# Enable reconnect from here.
DO_RECONNECT=$RECONNECT
# Now make it pass anchor (should be in mempool: one block to bury it)
check_tx_spend
$CLI generate 1
check_peerstate lcli1 STATE_NORMAL
check_peerstate lcli2 STATE_NORMAL
# We turn off routing failure for the moment.
lcli1 dev-routefail false
lcli2 dev-routefail false
A_AMOUNT=$(($AMOUNT - $NO_HTLCS_FEE))
A_FEE=$NO_HTLCS_FEE
B_AMOUNT=0
B_FEE=0
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE ""
# This is 10,000 satoshi, so not dust!
HTLC_AMOUNT=10000000
EXPIRY=$(( $(blockheight) + 10))
SECRET=1de08917a61cb2b62ed5937d38577f6a7bfe59c176781c6d8128018e8b5ccdfd
RHASH=`lcli1 dev-rhash $SECRET | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id`
if [ -n "$MANUALCOMMIT" ]; then
# They should register a staged htlc.
check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_HTLC } " $B_AMOUNT $B_FEE ""
# Now commit it.
lcli1 dev-commit $ID2
# Node 1 hasn't got it committed, but node2 should have told it to stage.
check_status_single lcli1 $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_ADD_REVOCATION } " $B_AMOUNT $B_FEE ""
# Check channel status
A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT))
A_FEE=$(($A_FEE + $EXTRA_FEE))
# Node 2 has it committed.
check_status_single lcli2 $B_AMOUNT $B_FEE "" $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_REVOCATION } "
# There should be no "both committed" here yet
if lcli1 getlog debug | $FGREP "Both committed"; then
echo "Node1 thinks they are both committed";
exit 1
fi
if lcli2 getlog debug | $FGREP "Both committed"; then
echo "Node2 thinks they are both committed";
exit 1
fi
# Now node2 gives commitment to node1.
lcli2 dev-commit $ID1
# After revocation, they should know they're both committed.
check lcli1 "getlog debug | $FGREP 'Both committed to ADD of our HTLC'"
check lcli2 "getlog debug | $FGREP 'Both committed to ADD of their HTLC'"
else
A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT))
A_FEE=$(($A_FEE + $EXTRA_FEE))
fi
# Both should have committed tx.
check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $B_AMOUNT $B_FEE ""
lcli2 dev-fulfillhtlc $ID1 $HTLCID $SECRET
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1
# Without manual commit, this check is racy.
if [ -n "$MANUALCOMMIT" ]; then
if lcli1 getlog debug | $FGREP 'Both committed to FULFILL'; then
echo "Node1 thinks they are both committed";
exit 1
fi
if lcli2 getlog debug | $FGREP 'Both committed to FULFILL'; then
echo "Node2 thinks they are both committed";
exit 1
fi
fi
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2
# If we're very slow, manually committed above, and we're restarting,
# we may restart *after* this and thus not see it in the log.
[ "$RECONNECT$MANUALCOMMIT" = restart1 ] || check lcli1 "getlog debug | $FGREP 'Both committed to FULFILL of our HTLC'"
check lcli2 "getlog debug | $FGREP 'Both committed to FULFILL of their HTLC'"
# We've transferred the HTLC amount to 2, who now has to pay fees,
# so no net change for A who saves on fees.
B_FEE=$HTLC_AMOUNT
# With no HTLCs, extra fee no longer required.
A_FEE=$(($A_FEE - $EXTRA_FEE - $B_FEE))
A_AMOUNT=$(($A_AMOUNT + $EXTRA_FEE + $HTLC_AMOUNT))
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE ""
# A new one, at 10x the amount.
HTLC_AMOUNT=100000000
HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id`
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1
# Check channel status
A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT))
A_FEE=$(($A_FEE + $EXTRA_FEE))
check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $B_AMOUNT $B_FEE ""
lcli2 dev-failhtlc $ID1 $HTLCID 695
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2
# Back to how we were before.
A_AMOUNT=$(($A_AMOUNT + $EXTRA_FEE + $HTLC_AMOUNT))
A_FEE=$(($A_FEE - $EXTRA_FEE))
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE ""
# Same again, but this time it expires.
HTLC_AMOUNT=10000001
HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id`
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1
# Check channel status
A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT))
A_FEE=$(($A_FEE + $EXTRA_FEE))
check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $B_AMOUNT $B_FEE ""
# Make sure node1 accepts the expiry packet.
while [ $(blockheight) != $EXPIRY ]; do
$CLI generate 1
done
# This should make node2 send it.
$CLI generate 1
if [ -n "$MANUALCOMMIT" ]; then
check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_REMOVE_HTLC } " $B_AMOUNT $B_FEE ""
lcli2 dev-commit $ID1
lcli1 dev-commit $ID2
fi
# Back to how we were before.
A_AMOUNT=$(($A_AMOUNT + $EXTRA_FEE + $HTLC_AMOUNT))
A_FEE=$(($A_FEE - $EXTRA_FEE))
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE ""
# First, give more money to node2, so it can offer HTLCs.
EXPIRY=$(( $(blockheight) + 10))
HTLC_AMOUNT=100000000
HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id`
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1
check_status $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $B_AMOUNT $B_FEE ""
lcli2 dev-fulfillhtlc $ID1 $HTLCID $SECRET
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2
# Both now pay equal fees.
A_FEE=$(($NO_HTLCS_FEE / 2))
B_FEE=$(($NO_HTLCS_FEE / 2))
# We transferred 10000000 before, and $HTLC_AMOUNT now.
A_AMOUNT=$(($AMOUNT - 10000000 - $HTLC_AMOUNT - $A_FEE))
B_AMOUNT=$((10000000 + $HTLC_AMOUNT - $B_FEE))
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE ""
# Two failures crossover
SECRET2=1de08917a61cb2b62ed5937d38577f6a7bfe59c176781c6d8128018e8b5ccdfe
RHASH2=`lcli1 dev-rhash $SECRET2 | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
# This means B will *just* afford it (but can't cover increased fees)
HTLC_AMOUNT=$(($B_AMOUNT - $EXTRA_FEE / 2))
HTLCID=`lcli2 dev-newhtlc $ID1 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id`
# Make sure that's committed, in case lcli1 restarts.
lcli2 dev-commit $ID1 >/dev/null || true
HTLCID2=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH2 | extract_id`
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1
# A covers the extra part of the fee.
check_status $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE - $EXTRA_FEE / 2)) $(($A_FEE + $EXTRA_FEE + $EXTRA_FEE / 2)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH2 , state : SENT_ADD_ACK_REVOCATION } " 0 $(($B_FEE + $EXTRA_FEE / 2)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_ADD_ACK_REVOCATION } "
# Fail both, to reset.
lcli1 dev-failhtlc $ID2 $HTLCID 830
lcli2 dev-failhtlc $ID1 $HTLCID2 829
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE ""
# Now, two HTLCs at once, one from each direction.
# Both sides can afford this.
HTLC_AMOUNT=1000000
HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id`
HTLCID2=`lcli2 dev-newhtlc $ID1 $HTLC_AMOUNT $EXPIRY $RHASH2 | extract_id`
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1
check_status $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $(($B_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($B_FEE + $EXTRA_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH2 , state : RCVD_ADD_ACK_REVOCATION } "
lcli1 dev-fulfillhtlc $ID2 $HTLCID2 $SECRET2
lcli2 dev-failhtlc $ID1 $HTLCID 849
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1
# We transferred amount from B to A.
A_AMOUNT=$(($A_AMOUNT + $HTLC_AMOUNT))
B_AMOUNT=$(($B_AMOUNT - $HTLC_AMOUNT))
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE ""
# Now, test making more changes before receiving commit reply.
DO_RECONNECT=""
lcli2 dev-output $ID1 false
HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id`
# Make sure node1 sends commit (in the background, since it will block!)
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2 &
if [ -n "$MANUALCOMMIT" ]; then
# node2 will consider this committed.
check_status_single lcli2 $(($B_AMOUNT - $EXTRA_FEE/2)) $(($B_FEE + $EXTRA_FEE/2)) "" $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE/2)) $(($A_FEE + $EXTRA_FEE/2)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_REVOCATION } "
else
# It will start committing by itself
check_status_single lcli2 $(($B_AMOUNT - $EXTRA_FEE/2)) $(($B_FEE + $EXTRA_FEE/2)) "" $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE/2)) $(($A_FEE + $EXTRA_FEE/2)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_COMMIT } "
fi
# node1 will still be awaiting node2's revocation reply.
check_status_single lcli1 $(($A_AMOUNT)) $(($A_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_COMMIT } " $B_AMOUNT $B_FEE ""
# Now send another offer, and enable node2 output.
HTLCID2=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH2 | extract_id`
lcli2 dev-output $ID1 true
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1
DO_RECONNECT=$RECONNECT
# Both sides should be committed to htlcs
# We open-code check_status here: HTLCs could be in either order.
check_balance_single lcli1 $(($A_AMOUNT - $HTLC_AMOUNT*2 - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) $(($B_AMOUNT - $EXTRA_FEE)) $(($B_FEE + $EXTRA_FEE))
check_balance_single lcli2 $(($B_AMOUNT - $EXTRA_FEE)) $(($B_FEE + $EXTRA_FEE)) $(($A_AMOUNT - $HTLC_AMOUNT*2 - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE))
# Once both balances are correct, this should be right.
lcli1 getpeers | tr -s '\012\011" ' ' ' | $FGREP "our_htlcs : [ { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION }, { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH2 , state : SENT_ADD_ACK_REVOCATION } ], their_htlcs : [ ]" || lcli1 getpeers | tr -s '\012\011" ' ' ' | $FGREP "our_htlcs : [ { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH2 , state : SENT_ADD_ACK_REVOCATION }, { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } ], their_htlcs : [ ]"
lcli2 getpeers | tr -s '\012\011" ' ' ' | $FGREP "our_htlcs : [ ], their_htlcs : [ { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_ADD_ACK_REVOCATION }, { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH2 , state : RCVD_ADD_ACK_REVOCATION } ]" || lcli2 getpeers | tr -s '\012\011" ' ' ' | $FGREP "our_htlcs : [ ], their_htlcs : [ { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH2 , state : RCVD_ADD_ACK_REVOCATION }, { msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_ADD_ACK_REVOCATION } ]"
# Just for once, reconnect/restart node 2.
case "$RECONNECT" in
reconnect)
echo RECONNECTING NODE2
$LCLI2 dev-reconnect $ID1 >/dev/null
sleep 1
;;
restart)
echo RESTARTING NODE2
$LCLI2 -- dev-restart $LIGHTNINGD2 >/dev/null 2>&1 || true
if ! check "$LCLI2 getlog 2>/dev/null | fgrep -q Hello"; then
echo "Node2 dev-restart failed!">&2
exit 1
fi
;;
esac
if ! check "$LCLI2 getpeers | tr -s '\012\011\" ' ' ' | fgrep -q 'connected : true'"; then
echo "Failed to reconnect!">&2
exit 1
fi
# Node2 collects the HTLCs.
lcli2 dev-fulfillhtlc $ID1 $HTLCID $SECRET
lcli2 dev-fulfillhtlc $ID1 $HTLCID2 $SECRET2
[ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1
[ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2
# We transferred 2 * amount from A to B.
A_AMOUNT=$(($A_AMOUNT - $HTLC_AMOUNT * 2))
B_AMOUNT=$(($B_AMOUNT + $HTLC_AMOUNT * 2))
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE ""
lcli1 close $ID2
# They should be negotiating the close.
check_peerstate lcli1 STATE_MUTUAL_CLOSING
check_peerstate lcli2 STATE_MUTUAL_CLOSING
$CLI generate 1
check_peerstate lcli1 STATE_CLOSE_ONCHAIN_MUTUAL
check_peerstate lcli2 STATE_CLOSE_ONCHAIN_MUTUAL
# Give it forever-1 blocks.
$CLI generate 8
# Make sure they saw it!
check_peerstate lcli1 STATE_CLOSE_ONCHAIN_MUTUAL
check_peerstate lcli2 STATE_CLOSE_ONCHAIN_MUTUAL
# Now the final one.
$CLI generate 1
check_no_peers lcli1
check_no_peers lcli2
lcli1 stop
lcli2 stop
all_ok

86
daemon/test/test-different-fees

@ -1,86 +0,0 @@
#! /bin/sh -e
# Wherever we are, we want to be in daemon/test dir.
cd `git rev-parse --show-toplevel`/daemon/test
. scripts/vars.sh
. scripts/helpers.sh
parse_cmdline 2 "$@"
setup_lightning 2
# Simply override default fee (estimatefee fails on regtest anyway)
DEFAULT_FEE_RATE2=50000
# We use 5x fee rate for commits, by defailt.
FEE_RATE2=$(($DEFAULT_FEE_RATE2 * 5))
echo "default-fee-rate=$DEFAULT_FEE_RATE2" >> $DIR2/config
start_lightningd 2
fund_lightningd
lcli1 connect localhost $PORT2 $FUND_INPUT_TX &
# Now make it pass anchor (should be in mempool: one block to bury it)
check_tx_spend
$CLI generate 1
DO_RECONNECT=$RECONNECT
check_peerstate lcli1 STATE_NORMAL
check_peerstate lcli2 STATE_NORMAL
# Asymmetry, since fee rates different.
NO_HTLCS_FEE2=$((338 * $FEE_RATE2 / 2000 * 2000))
ONE_HTLCS_FEE2=$(( (338 + 32) * $FEE_RATE2 / 2000 * 2000))
A_AMOUNT1=$(($AMOUNT - $NO_HTLCS_FEE))
A_FEE1=$NO_HTLCS_FEE
A_AMOUNT2=$(($AMOUNT - $NO_HTLCS_FEE2))
A_FEE2=$NO_HTLCS_FEE2
B_AMOUNT=0
B_FEE=0
check_status_single lcli1 $A_AMOUNT1 $A_FEE1 "" $B_AMOUNT $B_FEE ""
check_status_single lcli2 $B_AMOUNT $B_FEE "" $(($A_AMOUNT2)) $(($A_FEE2)) ""
# This is 100,000 satoshi, so covers fees.
HTLC_AMOUNT=100000000
RHASH=`lcli2 invoice $HTLC_AMOUNT RHASH3 | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
ROUTE=`lcli1 getroute $ID2 $HTLC_AMOUNT 1`
ROUTE=`echo $ROUTE | sed 's/^{ "route" : \(.*\) }$/\1/'`
lcli1 sendpay "$ROUTE" $RHASH
# They should not split fees.
check_status_single lcli1 $(($AMOUNT - $HTLC_AMOUNT - $NO_HTLCS_FEE / 2)) $(($NO_HTLCS_FEE / 2)) "" $(($HTLC_AMOUNT - $NO_HTLCS_FEE / 2)) $(($NO_HTLCS_FEE / 2)) ""
check_status_single lcli2 $(($HTLC_AMOUNT - $NO_HTLCS_FEE2 / 2)) $(($NO_HTLCS_FEE2 / 2)) "" $(($AMOUNT - $HTLC_AMOUNT - $NO_HTLCS_FEE2 / 2)) $(($NO_HTLCS_FEE2 / 2)) ""
# FIXME: reactivate feechanges!
# # Change fee rate on node2 to same as node1.
# lcli2 dev-feerate 40000
# $CLI generate 1
# [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1
# [ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2
# check_status $(($AMOUNT - $HTLC_AMOUNT - $NO_HTLCS_FEE / 2)) $(($NO_HTLCS_FEE / 2)) "" $(($HTLC_AMOUNT - $NO_HTLCS_FEE / 2)) $(($NO_HTLCS_FEE / 2)) ""
# # Change back.
# lcli2 dev-feerate 50000
# $CLI generate 1
# [ ! -n "$MANUALCOMMIT" ] || lcli2 dev-commit $ID1
# [ ! -n "$MANUALCOMMIT" ] || lcli1 dev-commit $ID2
# check_status_single lcli1 $(($AMOUNT - $HTLC_AMOUNT - $NO_HTLCS_FEE / 2)) $(($NO_HTLCS_FEE / 2)) "" $(($HTLC_AMOUNT - $NO_HTLCS_FEE / 2)) $(($NO_HTLCS_FEE / 2)) ""
# check_status_single lcli2 $(($HTLC_AMOUNT - $NO_HTLCS_FEE2 / 2)) $(($NO_HTLCS_FEE2 / 2)) "" $(($AMOUNT - $HTLC_AMOUNT - $NO_HTLCS_FEE2 / 2)) $(($NO_HTLCS_FEE2 / 2)) ""
lcli1 close $ID2
check_tx_spend
# Give it 10 blocks ie "forever"
$CLI generate 10
check_no_peers lcli1
check_no_peers lcli2
lcli1 stop
lcli2 stop
all_ok

82
daemon/test/test-funding-timeout

@ -1,82 +0,0 @@
#! /bin/sh -e
# Wherever we are, we want to be in daemon/test dir.
cd `git rev-parse --show-toplevel`/daemon/test
. scripts/vars.sh
. scripts/helpers.sh
parse_cmdline 2 "$@"
setup_lightning 2
start_lightningd 2
fund_lightningd
# Prevent anchor broadcast
lcli1 dev-broadcast false
lcli1 connect localhost $PORT2 $FUND_INPUT_TX &
# Expect them to be waiting for anchor, and ack from other side.
check_peerstate lcli1 STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE
check_peerstate lcli2 STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE
# Enable reconnect from here.
DO_RECONNECT=$RECONNECT
$CLI generate 99
# Still waiting.
check_peerstate lcli1 STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE
check_peerstate lcli2 STATE_OPEN_WAIT_ANCHORDEPTH_AND_THEIRCOMPLETE
# Make sure whichever times out first doesn't tell the other.
lcli1 dev-output $ID2 false
lcli2 dev-output $ID1 false
$CLI generate 1
# Node1 should have gone into STATE_ERR_ANCHOR_TIMEOUT.
check "lcli1 getlog debug | $FGREP STATE_ERR_ANCHOR_TIMEOUT"
# Don't try to reconnect any more if we are.
if [ x"$RECONNECT" = xreconnect ]; then DO_RECONNECT=""; fi
# If we're restarting, don't expect peer.
NO_PEER2=1
# Now let them send errors if they're still trying.
lcli2 dev-output $ID1 true || true
lcli1 dev-output $ID2 true || true
# Peer 2 should give up, and have forgotten all about it.
check "lcli2 getlog debug | $FGREP STATE_CLOSED"
check_no_peers lcli2
# Node1 should be disconnected.
check_peerconnected lcli1 false
# Now let node1 broadcast anchor and unilateral close belatedly!
lcli1 dev-broadcast true
# Now mine that transaction so they see it.
$CLI generate 1
check_peerstate lcli1 STATE_CLOSE_ONCHAIN_OUR_UNILATERAL
# Now move bitcoind 1 day, which is what node2 asked for on commit.
# Get current time from last block (works if we run this twice).
CURTIME=$($CLI getblock $($CLI getblockhash $(($BLOCKHEIGHT + 100))) | sed -n 's/ "time": \([0-9]*\),/\1/p')
$CLI setmocktime $(($CURTIME + 24 * 60 * 60))
# Move average so CSV moves.
$CLI generate 6
# Now it should have spent the commit tx.
check_tx_spend
# 100 blocks pass
$CLI generate 100
# Considers it all done now.
check_no_peers lcli1
lcli1 stop
lcli2 stop
all_ok

87
daemon/test/test-invoice

@ -1,87 +0,0 @@
#! /bin/sh -e
# Wherever we are, we want to be in daemon/test dir.
cd `git rev-parse --show-toplevel`/daemon/test
. scripts/vars.sh
. scripts/helpers.sh
parse_cmdline 2 "$@"
setup_lightning 2
start_lightningd 2
fund_lightningd
lcli1 connect localhost $PORT2 $FUND_INPUT_TX &
# Now make it pass anchor (should be in mempool: one block to bury it)
check_tx_spend
$CLI generate 1
DO_RECONNECT=$RECONNECT
check_peerstate lcli1 STATE_NORMAL
check_peerstate lcli2 STATE_NORMAL
A_AMOUNT=$(($AMOUNT - $NO_HTLCS_FEE))
A_FEE=$NO_HTLCS_FEE
B_AMOUNT=0
B_FEE=0
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE ""
# 100k satoshi should cover fees.
HTLC_AMOUNT=100000000
EXPIRY=$(( $(blockheight) + 10))
RHASH3=`lcli2 invoice $HTLC_AMOUNT RHASH3 | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
lcli2 listinvoice
[ "`lcli2 listinvoice | tr -s '\012\011\" ' ' '`" = "[ { label : RHASH3 , rhash : $RHASH3 , msatoshi : $HTLC_AMOUNT, complete : false } ] " ]
HTLCID3=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH3 | extract_id`
# We transferred amount from A to B, but fee now split evenly.
A_AMOUNT=$(($A_AMOUNT - $HTLC_AMOUNT + $NO_HTLCS_FEE / 2))
B_AMOUNT=$(($B_AMOUNT + $HTLC_AMOUNT - $NO_HTLCS_FEE / 2))
A_FEE=$(($NO_HTLCS_FEE / 2))
B_FEE=$(($NO_HTLCS_FEE / 2))
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE ""
[ "`lcli2 listinvoice | tr -s '\012\011\" ' ' '`" = "[ { label : RHASH3 , rhash : $RHASH3 , msatoshi : $HTLC_AMOUNT, complete : true } ] " ]
# Now, failed payment (didn't pay enough)
RHASH4=`lcli2 invoice $HTLC_AMOUNT RHASH4 | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
# Shouldn't have this already.
if lcli2 getlog | $FGREP 'Short payment for'; then exit 1; fi
# Test listinvoice with both, or subset (either order possible!)
INVOICES=`lcli2 listinvoice | tr -s '\012\011\" ' ' '`
[ "$INVOICES" = "[ { label : RHASH3 , rhash : $RHASH3 , msatoshi : $HTLC_AMOUNT, complete : true }, { label : RHASH4 , rhash : $RHASH4 , msatoshi : $HTLC_AMOUNT, complete : false } ] " ] || [ "$INVOICES" = "[ { label : RHASH4 , rhash : $RHASH4 , msatoshi : $HTLC_AMOUNT, complete : false }, { label : RHASH3 , rhash : $RHASH3 , msatoshi : $HTLC_AMOUNT, complete : true } ] " ]
[ "`lcli2 listinvoice RHASH3 | tr -s '\012\011\" ' ' '`" = "[ { label : RHASH3 , rhash : $RHASH3 , msatoshi : $HTLC_AMOUNT, complete : true } ] " ]
[ "`lcli2 listinvoice RHASH4 | tr -s '\012\011\" ' ' '`" = "[ { label : RHASH4 , rhash : $RHASH4 , msatoshi : $HTLC_AMOUNT, complete : false } ] " ]
HTLCID4=`lcli1 dev-newhtlc $ID2 $(($HTLC_AMOUNT - 1)) $EXPIRY $RHASH4 | extract_id`
check lcli2 "getlog | $FGREP 'Short payment for'"
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE ""
lcli2 delinvoice RHASH4
if lcli2 delinvoice RHASH3 >/dev/null; then
echo "Should not be able to delete completed invoice!" >&2
exit 1
fi
lcli1 close $ID2
# They should be negotiate the close.
check_tx_spend
# Bury it in "forever" blocks.
$CLI generate 10
check_no_peers lcli1
check_no_peers lcli2
lcli1 stop
lcli2 stop
all_ok

96
daemon/test/test-mutual-close-with-htlcs

@ -1,96 +0,0 @@
#! /bin/sh -e
# Wherever we are, we want to be in daemon/test dir.
cd `git rev-parse --show-toplevel`/daemon/test
. scripts/vars.sh
. scripts/helpers.sh
parse_cmdline 2 "$@"
setup_lightning 2
start_lightningd 2
fund_lightningd
lcli1 connect localhost $PORT2 $FUND_INPUT_TX &
# Now make it pass anchor (should be in mempool: one block to bury it)
check_tx_spend
$CLI generate 1
DO_RECONNECT=$RECONNECT
check_peerstate lcli1 STATE_NORMAL
check_peerstate lcli2 STATE_NORMAL
A_AMOUNT=$(($AMOUNT - $NO_HTLCS_FEE))
A_FEE=$NO_HTLCS_FEE
B_AMOUNT=0
B_FEE=0
# Send funds to 2 so it can offer HTLCS
HTLC_AMOUNT=100000000
RHASH=`lcli2 invoice $HTLC_AMOUNT RHASH3 | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
ROUTE=`lcli1 getroute $ID2 $HTLC_AMOUNT 1`
ROUTE=`echo $ROUTE | sed 's/^{ "route" : \(.*\) }$/\1/'`
lcli1 sendpay "$ROUTE" $RHASH
# They pay half fees each.
A_AMOUNT=$(($A_AMOUNT - $HTLC_AMOUNT + $NO_HTLCS_FEE / 2))
A_FEE=$(($NO_HTLCS_FEE / 2))
B_AMOUNT=$(($B_AMOUNT + $HTLC_AMOUNT - $NO_HTLCS_FEE / 2))
B_FEE=$(($NO_HTLCS_FEE / 2))
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE ""
# For next step, make sure neither node fails HTLCs we're about to set up.
lcli1 dev-routefail false
lcli2 dev-routefail false
# Set up HTLCs both ways.
# This is 10,000 satoshi, so not dust!
HTLC_AMOUNT=10000000
EXPIRY=$(( $(blockheight) + 10))
SECRET=1de08917a61cb2b62ed5937d38577f6a7bfe59c176781c6d8128018e8b5ccdfd
RHASH=`lcli1 dev-rhash $SECRET | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
HTLCID1=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id`
# FIXME: Test with dust htlc, too.
HTLCID2=`lcli2 dev-newhtlc $ID1 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id`
check_status $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $(($B_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($B_FEE + $EXTRA_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_ADD_ACK_REVOCATION } "
# Now begin close
lcli1 close $ID2
# They should be waiting for it to clear up.
check_peerstate lcli1 STATE_SHUTDOWN
check_peerstate lcli2 STATE_SHUTDOWN
# Fail one, still waiting.
lcli2 dev-failhtlc $ID1 $HTLCID1 800
check_peerstate lcli1 STATE_SHUTDOWN
check_peerstate lcli2 STATE_SHUTDOWN
# Fulfill the other causes them to actually complete the close.
lcli1 dev-fulfillhtlc $ID2 $HTLCID2 $SECRET
check_peerstate lcli1 STATE_MUTUAL_CLOSING
check_peerstate lcli2 STATE_MUTUAL_CLOSING
check_tx_spend
$CLI generate 1
check_peerstate lcli1 STATE_CLOSE_ONCHAIN_MUTUAL
check_peerstate lcli2 STATE_CLOSE_ONCHAIN_MUTUAL
# Give it "forever" blocks.
$CLI generate 9
check_no_peers lcli1
check_no_peers lcli2
lcli1 stop
lcli2 stop
all_ok

146
daemon/test/test-routing

@ -1,146 +0,0 @@
#! /bin/sh -e
# Wherever we are, we want to be in daemon/test dir.
cd `git rev-parse --show-toplevel`/daemon/test
. scripts/vars.sh
. scripts/helpers.sh
parse_cmdline 3 "$@"
setup_lightning 3
start_lightningd 3
fund_lightningd
# We connect 1->2->3
lcli1 connect localhost $PORT2 $FUND_INPUT_TX &
check_tx_spend
$CLI generate 1
P2SHADDR2=`$LCLI2 newaddr | sed -n 's/{ "address" : "\(.*\)" }/\1/p'`
TXID2=`$CLI sendtoaddress $P2SHADDR2 0.01`
FUND_INPUT_TX2=`$CLI getrawtransaction $TXID2`
$CLI generate 1
lcli2 connect localhost $PORT3 $FUND_INPUT_TX2 &
check_tx_spend
$CLI generate 1
DO_RECONNECT=$RECONNECT
# Make sure all in STATE_NORMAL.
check_peerstate lcli1 STATE_NORMAL
check_peerstate lcli3 STATE_NORMAL
# More than enough to cover commit fees.
HTLC_AMOUNT=100000000
# Tell node 1 about the 2->3 route.
# Add to config in case we are restaring.
echo "add-route=$ID2/$ID3/546000/10/36/36" >> $DIR1/config
lcli1 dev-add-route $ID2 $ID3 546000 10 36 36
RHASH=`lcli3 invoice $HTLC_AMOUNT RHASH | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
BAD_RHASH=`echo $RHASH | tr '0-9a-f' 'a-f0-9'`
# Get route.
ROUTE=`lcli1 getroute $ID3 $HTLC_AMOUNT 1`
ROUTE=`echo $ROUTE | sed 's/^{ "route" : \(.*\) }$/\1/'`
# Try wrong hash.
if lcli1 sendpay "$ROUTE" $BAD_RHASH; then
echo Paid with wrong hash? >&2
exit 1
fi
# Try underpaying.
PAID=`echo "$ROUTE" | sed -n 's/.*"msatoshi" : \([0-9]*\),.*/\1/p'`
UNDERPAY=`echo "$ROUTE" | sed "s/: $PAID,/: $(($PAID - 1)),/"`
if lcli1 sendpay "$UNDERPAY" $RHASH; then
echo Paid with too little? >&2
exit 1
fi
# If restarting, make sure node3 remembers incoming payment.
if [ "$RECONNECT" = restart ]; then
$LCLI3 -- dev-restart $LIGHTNINGD3 >/dev/null 2>&1 || true
if ! check "$LCLI3 getpeers 2>/dev/null | tr -s '\012\011\" ' ' ' | fgrep -q 'connected : true'"; then
echo "Failed to reconnect!">&2
exit 1
fi
fi
[ "`lcli3 listinvoice RHASH | tr -s '\012\011\" ' ' '`" = "[ { label : RHASH , rhash : $RHASH , msatoshi : $HTLC_AMOUNT, complete : false } ] " ]
# Pay correctly.
lcli1 sendpay "$ROUTE" $RHASH
# Node 3 should end up with that amount (minus 1/2 tx fee)
# Note that it is delayed a little, since node2 fulfils as soon as fulfill
# starts.
check lcli3 "getpeers | $FGREP \"\\\"our_amount\\\" : $(($HTLC_AMOUNT - $NO_HTLCS_FEE / 2))\""
# If restarting, make sure node3 remembers completed payment.
if [ "$RECONNECT" = restart ]; then
echo RESTARTING NODE3
$LCLI3 -- dev-restart $LIGHTNINGD3 >/dev/null 2>&1 || true
sleep 5
$LCLI2 -- dev-restart $LIGHTNINGD2 >/dev/null 2>&1 || true
if ! check "$LCLI3 getpeers 2>/dev/null | tr -s '\012\011\" ' ' ' | fgrep -q 'connected : true'"; then
echo "Failed to reconnect!">&2
exit 1
fi
fi
[ "`lcli3 listinvoice RHASH | tr -s '\012\011\" ' ' '`" = "[ { label : RHASH , rhash : $RHASH , msatoshi : $HTLC_AMOUNT, complete : true } ] " ]
[ "`lcli3 waitanyinvoice | tr -s '\012\011\" ' ' '`" = "{ label : RHASH , rhash : $RHASH , msatoshi : $HTLC_AMOUNT } " ]
# Can't pay twice (try from node2)
ROUTE2=`lcli2 getroute $ID3 $HTLC_AMOUNT 1`
ROUTE2=`echo $ROUTE2 | sed 's/^{ "route" : \(.*\) }$/\1/'`
if lcli2 sendpay "$ROUTE2" $RHASH; then
echo "Paying twice worked?" >&2
exit 1
fi
lcli3 close $ID2
check_peerstate lcli3 STATE_MUTUAL_CLOSING
# Re-send should be a noop (doesn't matter that node3 is down!)
lcli1 sendpay "$ROUTE" $RHASH
# Re-send to different id or amount should complain.
SHORTROUTE=`echo "$ROUTE" | sed 's/, { "id" : .* }//' | sed 's/"msatoshi" : [0-9]*,/"msatoshi" : '$HTLC_AMOUNT,/`
lcli1 sendpay "$SHORTROUTE" $RHASH | $FGREP "already succeeded to $ID3"
lcli1 sendpay "$UNDERPAY" $RHASH | $FGREP "already succeeded with amount $HTLC_AMOUNT"
# Now node2 should fail to route.
if lcli1 sendpay "$ROUTE" $BAD_RHASH | $FGREP "failed: error code 404 node $ID2 reason Unknown peer"; then : ;
else
echo "Pay to node3 didn't give 404" >&2
exit 1
fi
# Now node1 should fail to route (route deleted)
if lcli1 getroute $ID3 $HTLC_AMOUNT 1 | $FGREP "no route found"; then : ;
else
echo "Pay to node3 didn't fail instantly second time" >&2
exit 1
fi
lcli1 close $ID2
check_peerstate lcli1 STATE_MUTUAL_CLOSING
# Make sure both txs broadcast.
check '[ `$CLI getrawmempool | egrep -c "[a-f0-9]{32}"` = 2 ]'
# Bury them in "forever" blocks.
$CLI generate 10
check_no_peers lcli1
check_no_peers lcli2
check_no_peers lcli3
lcli1 stop
lcli2 stop
lcli3 stop
all_ok

91
daemon/test/test-steal

@ -1,91 +0,0 @@
#! /bin/sh -e
# Wherever we are, we want to be in daemon/test dir.
cd `git rev-parse --show-toplevel`/daemon/test
. scripts/vars.sh
. scripts/helpers.sh
parse_cmdline 2 "$@"
setup_lightning 2
start_lightningd 2
fund_lightningd
lcli1 connect localhost $PORT2 $FUND_INPUT_TX &
# Now make it pass anchor (should be in mempool: one block to bury it)
check_tx_spend
$CLI generate 1
DO_RECONNECT=$RECONNECT
check_peerstate lcli1 STATE_NORMAL
check_peerstate lcli2 STATE_NORMAL
A_AMOUNT=$(($AMOUNT - $NO_HTLCS_FEE))
A_FEE=$NO_HTLCS_FEE
B_AMOUNT=0
B_FEE=0
# Send funds to 2 so it can offer HTLCS
HTLC_AMOUNT=100000000
RHASH=`lcli2 invoice $HTLC_AMOUNT RHASH3 | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
ROUTE=`lcli1 getroute $ID2 $HTLC_AMOUNT 1`
ROUTE=`echo $ROUTE | sed 's/^{ "route" : \(.*\) }$/\1/'`
lcli1 sendpay "$ROUTE" $RHASH
# They pay half fees each noe.
A_AMOUNT=$(($A_AMOUNT - $HTLC_AMOUNT + $NO_HTLCS_FEE / 2))
A_FEE=$(($NO_HTLCS_FEE / 2))
B_AMOUNT=$(($B_AMOUNT + $HTLC_AMOUNT - $NO_HTLCS_FEE / 2))
B_FEE=$(($NO_HTLCS_FEE / 2))
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE ""
# For next step, make sure neither node fails HTLCs we're about to set up.
lcli1 dev-routefail false
lcli2 dev-routefail false
# Set up HTLCs both ways.
# This is 10,000 satoshi, so not dust!
HTLC_AMOUNT=10000000
EXPIRY=$(( $(blockheight) + 10))
SECRET=1de08917a61cb2b62ed5937d38577f6a7bfe59c176781c6d8128018e8b5ccdfd
RHASH=`lcli1 dev-rhash $SECRET | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
HTLCID1=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id`
# FIXME: Test with dust htlc, too.
HTLCID2=`lcli2 dev-newhtlc $ID1 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id`
check_status $(($A_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($A_FEE + $EXTRA_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $(($B_AMOUNT - $HTLC_AMOUNT - $EXTRA_FEE)) $(($B_FEE + $EXTRA_FEE)) "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : RCVD_ADD_ACK_REVOCATION } "
# This is the tx we're going to try to spend.
STEAL_TX=`$LCLI1 dev-signcommit $ID2 | cut -d\" -f4`
# Fail one, succeed 2->1 payment
lcli2 dev-failhtlc $ID1 $HTLCID1 800
lcli1 dev-fulfillhtlc $ID2 $HTLCID2 $SECRET
A_AMOUNT=$(($A_AMOUNT + $HTLC_AMOUNT))
B_AMOUNT=$(($B_AMOUNT - $HTLC_AMOUNT))
check_status $A_AMOUNT $A_FEE "" $B_AMOUNT $B_FEE ""
# Send out old commit tx from peer 1.
$CLI sendrawtransaction $STEAL_TX
$CLI generate 1
# Node1 should get really upset; node2 should steal the transaction.
check_peerstate lcli1 STATE_ERR_INFORMATION_LEAK
check_peerstate lcli2 STATE_CLOSE_ONCHAIN_CHEATED
check_tx_spend
# Give it "forever" blocks.
$CLI generate 10
check_no_peers lcli2
lcli1 stop
lcli2 stop
all_ok

87
daemon/test/test-unilateral

@ -1,87 +0,0 @@
#! /bin/sh -e
# Wherever we are, we want to be in daemon/test dir.
cd `git rev-parse --show-toplevel`/daemon/test
. scripts/vars.sh
. scripts/helpers.sh
parse_cmdline 2 "$@"
setup_lightning 2
start_lightningd 2
fund_lightningd
lcli1 connect localhost $PORT2 $FUND_INPUT_TX &
# Now make it pass anchor (should be in mempool: one block to bury it)
check_tx_spend
$CLI generate 1
DO_RECONNECT=$RECONNECT
check_peerstate lcli1 STATE_NORMAL
check_peerstate lcli2 STATE_NORMAL
# Make sure node2 doesn't fail
lcli2 dev-routefail false
A_AMOUNT=$(($AMOUNT - $NO_HTLCS_FEE))
A_FEE=$NO_HTLCS_FEE
B_AMOUNT=0
B_FEE=0
# This is 10,000 satoshi, so not dust!
HTLC_AMOUNT=10000000
EXPIRY=$(( $(blockheight) + 10))
SECRET=1de08917a61cb2b62ed5937d38577f6a7bfe59c176781c6d8128018e8b5ccdfd
RHASH=`lcli1 dev-rhash $SECRET | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
HTLCID=`lcli1 dev-newhtlc $ID2 $HTLC_AMOUNT $EXPIRY $RHASH | extract_id`
A_AMOUNT=$(($A_AMOUNT - $EXTRA_FEE - $HTLC_AMOUNT))
A_FEE=$(($A_FEE + $EXTRA_FEE))
B_AMOUNT=0
B_FEE=0
# Wait for both to committed.
check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $B_AMOUNT $B_FEE ""
# make node1 disconnect with node2.
lcli1 dev-disconnect $ID2
check_peerconnected lcli1 false
# lcli1 should have sent out commitment tx
check_peerstate lcli1 STATE_ERR_BREAKDOWN
check_tx_spend
# Mine it.
$CLI generate 1
check_peerstate lcli1 STATE_CLOSE_ONCHAIN_OUR_UNILATERAL
check_peerstate lcli2 STATE_CLOSE_ONCHAIN_THEIR_UNILATERAL
# both still know about htlc
check_status $A_AMOUNT $A_FEE "{ msatoshi : $HTLC_AMOUNT, expiry : { block : $EXPIRY }, rhash : $RHASH , state : SENT_ADD_ACK_REVOCATION } " $B_AMOUNT $B_FEE ""
# Generate 6 blocks so CSV timeout has expired.
$CLI generate 6
# Now, lcli1 should spend its own output.
check_tx_spend
check_peerstate lcli1 STATE_CLOSE_ONCHAIN_OUR_UNILATERAL
while [ $(blockheight) != $EXPIRY ]; do
$CLI generate 1
done
# lcli1 should have gotten HTLC back.
check_tx_spend
# Now, after "forever" blocks, should all be concluded.
$CLI generate 10
# Both consider it all done now.
check_no_peers lcli1
lcli1 stop
all_ok

144
daemon/wallet.c

@ -1,144 +0,0 @@
/* Poor man's wallet.
* Needed because bitcoind doesn't (yet) produce segwit outputs, and we need
* such outputs for our anchor tx to make it immalleable.
*/
#include "bitcoin/base58.h"
#include "bitcoin/privkey.h"
#include "bitcoin/script.h"
#include "bitcoin/signature.h"
#include "bitcoin/tx.h"
#include "db.h"
#include "jsonrpc.h"
#include "lightningd.h"
#include "log.h"
#include "wallet.h"
#include <ccan/structeq/structeq.h>
#include <sodium/randombytes.h>
struct wallet {
struct list_node list;
struct privkey privkey;
struct pubkey pubkey;
struct ripemd160 p2sh;
};
bool restore_wallet_address(struct lightningd_state *dstate,
const struct privkey *privkey)
{
struct wallet *w = tal(dstate, struct wallet);
u8 *redeemscript;
struct sha256 h;
w->privkey = *privkey;
if (!pubkey_from_privkey(&w->privkey, &w->pubkey))
return false;
redeemscript = bitcoin_redeem_p2sh_p2wpkh(w, &w->pubkey);
sha256(&h, redeemscript, tal_count(redeemscript));
ripemd160(&w->p2sh, h.u.u8, sizeof(h));
list_add_tail(&dstate->wallet, &w->list);
tal_free(redeemscript);
return true;
}
static void new_keypair(struct privkey *privkey, struct pubkey *pubkey)
{
do {
randombytes_buf(privkey->secret.data,
sizeof(privkey->secret.data));
} while (!pubkey_from_privkey(privkey, pubkey));
}
static struct wallet *find_by_pubkey(struct lightningd_state *dstate,
const struct pubkey *walletkey)
{
struct wallet *w;
list_for_each(&dstate->wallet, w, list) {
if (pubkey_eq(walletkey, &w->pubkey))
return w;
}
return NULL;
}
bool wallet_add_signed_input(struct lightningd_state *dstate,
const struct pubkey *walletkey,
struct bitcoin_tx *tx,
unsigned int input_num)
{
u8 *redeemscript;
secp256k1_ecdsa_signature sig;
struct wallet *w = find_by_pubkey(dstate, walletkey);
assert(input_num < tal_count(tx->input));
if (!w)
return false;
redeemscript = bitcoin_redeem_p2sh_p2wpkh(tx, &w->pubkey);
sign_tx_input(tx, input_num,
redeemscript,
p2wpkh_scriptcode(redeemscript, &w->pubkey),
&w->privkey,
&w->pubkey,
&sig);
bitcoin_witness_p2sh_p2wpkh(tx->input,
&tx->input[input_num],
&sig,
&w->pubkey);
tal_free(redeemscript);
return true;
}
bool wallet_can_spend(struct lightningd_state *dstate,
const struct bitcoin_tx_output *output,
struct pubkey *walletkey)
{
struct ripemd160 h;
struct wallet *w;
if (!is_p2sh(output->script))
return NULL;
memcpy(&h, output->script + 2, 20);
list_for_each(&dstate->wallet, w, list) {
if (structeq(&h, &w->p2sh)) {
*walletkey = w->pubkey;
return true;
}
}
return false;
}
static void json_newaddr(struct command *cmd,
const char *buffer, const jsmntok_t *params)
{
struct json_result *response = new_json_result(cmd);
struct wallet *w = tal(cmd->dstate, struct wallet);
u8 *redeemscript;
struct sha256 h;
new_keypair(&w->privkey, &w->pubkey);
redeemscript = bitcoin_redeem_p2sh_p2wpkh(cmd, &w->pubkey);
sha256(&h, redeemscript, tal_count(redeemscript));
ripemd160(&w->p2sh, h.u.u8, sizeof(h));
list_add_tail(&cmd->dstate->wallet, &w->list);
db_add_wallet_privkey(cmd->dstate, &w->privkey);
json_object_start(response, NULL);
json_add_string(response, "address",
p2sh_to_base58(cmd, cmd->dstate->testnet, &w->p2sh));
json_object_end(response);
command_success(cmd, response);
}
static const struct json_command newaddr_command = {
"newaddr",
json_newaddr,
"Get a new address to fund a channel",
"Returns {address} a p2sh address"
};
AUTODATA(json_command, &newaddr_command);

21
daemon/wallet.h

@ -1,21 +0,0 @@
#ifndef LIGHTNING_DAEMON_WALLET_H
#define LIGHTNING_DAEMON_WALLET_H
#include "config.h"
struct lightningd_state;
struct bitcoin_tx;
struct bitcoin_tx_output;
bool restore_wallet_address(struct lightningd_state *dstate,
const struct privkey *privkey);
bool wallet_add_signed_input(struct lightningd_state *dstate,
const struct pubkey *walletkey,
struct bitcoin_tx *tx,
unsigned int input_num);
bool wallet_can_spend(struct lightningd_state *dstate,
const struct bitcoin_tx_output *output,
struct pubkey *walletkey);
#endif /* LIGHTNING_DAEMON_WALLET_H */

4
daemon/watch.c

@ -32,7 +32,6 @@
#include "chaintopology.h" #include "chaintopology.h"
#include "lightningd.h" #include "lightningd.h"
#include "log.h" #include "log.h"
#include "peer.h"
#include "pseudorand.h" #include "pseudorand.h"
#include "timeout.h" #include "timeout.h"
#include "watch.h" #include "watch.h"
@ -160,6 +159,9 @@ struct txowatch *watch_txo_(const tal_t *ctx,
return w; return w;
} }
/* UNIFICATION FIXME */
void peer_debug(struct peer *peer, const char *fmt, ...);
/* Returns true if we fired a callback */ /* Returns true if we fired a callback */
static bool txw_fire(struct chain_topology *topo, static bool txw_fire(struct chain_topology *topo,
struct txwatch *txw, struct txwatch *txw,

151
tests/test_lightningd.py

@ -2,7 +2,7 @@ from binascii import hexlify, unhexlify
from concurrent import futures from concurrent import futures
from decimal import Decimal from decimal import Decimal
from hashlib import sha256 from hashlib import sha256
from lightning import LightningRpc, LegacyLightningRpc from lightning import LightningRpc
import copy import copy
import json import json
@ -86,7 +86,7 @@ class NodeFactory(object):
self.nodes = [] self.nodes = []
self.executor = executor self.executor = executor
def get_node(self, legacy=True, disconnect=None): def get_node(self, disconnect=None):
node_id = self.next_id node_id = self.next_id
self.next_id += 1 self.next_id += 1
@ -95,17 +95,13 @@ class NodeFactory(object):
socket_path = os.path.join(lightning_dir, "lightning-rpc").format(node_id) socket_path = os.path.join(lightning_dir, "lightning-rpc").format(node_id)
port = 16330+node_id port = 16330+node_id
if legacy: daemon = utils.LightningD(lightning_dir, bitcoind.bitcoin_dir, port=port)
daemon = utils.LegacyLightningD(lightning_dir, bitcoind.bitcoin_dir, port=port) # If we have a disconnect string, dump it to a file for daemon.
rpc = LegacyLightningRpc(socket_path, self.executor) if disconnect:
else: with open(os.path.join(lightning_dir, "dev_disconnect"), "w") as f:
daemon = utils.LightningD(lightning_dir, bitcoind.bitcoin_dir, port=port) f.write("\n".join(disconnect))
# If we have a disconnect string, dump it to a file for daemon. daemon.cmd_line.append("--dev-disconnect=dev_disconnect")
if disconnect: rpc = LightningRpc(socket_path, self.executor)
with open(os.path.join(lightning_dir, "dev_disconnect"), "w") as f:
f.write("\n".join(disconnect))
daemon.cmd_line.append("--dev-disconnect=dev_disconnect")
rpc = LightningRpc(socket_path, self.executor)
node = utils.LightningNode(daemon, rpc, bitcoind, self.executor) node = utils.LightningNode(daemon, rpc, bitcoind, self.executor)
self.nodes.append(node) self.nodes.append(node)
@ -170,8 +166,8 @@ class BaseLightningDTests(unittest.TestCase):
class LightningDTests(BaseLightningDTests): class LightningDTests(BaseLightningDTests):
def connect(self): def connect(self):
l1 = self.node_factory.get_node(legacy=False) l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node(legacy=False) l2 = self.node_factory.get_node()
ret = l1.rpc.connect('localhost', l2.info['port'], l2.info['id']) ret = l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
assert ret['id'] == l2.info['id'] assert ret['id'] == l2.info['id']
@ -401,8 +397,8 @@ class LightningDTests(BaseLightningDTests):
def test_permfail_new_commit(self): def test_permfail_new_commit(self):
# Test case where we have two possible commits: it will use new one. # Test case where we have two possible commits: it will use new one.
disconnects = ['-WIRE_REVOKE_AND_ACK', 'permfail'] disconnects = ['-WIRE_REVOKE_AND_ACK', 'permfail']
l1 = self.node_factory.get_node(legacy=False) l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node(legacy=False, disconnect=disconnects) l2 = self.node_factory.get_node(disconnect=disconnects)
l1.rpc.connect('localhost', l2.info['port'], l2.info['id']) l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
@ -440,8 +436,8 @@ class LightningDTests(BaseLightningDTests):
def test_permfail_htlc_in(self): def test_permfail_htlc_in(self):
# Test case where we fail with unsettled incoming HTLC. # Test case where we fail with unsettled incoming HTLC.
disconnects = ['-WIRE_UPDATE_FULFILL_HTLC', 'permfail'] disconnects = ['-WIRE_UPDATE_FULFILL_HTLC', 'permfail']
l1 = self.node_factory.get_node(legacy=False) l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node(legacy=False, disconnect=disconnects) l2 = self.node_factory.get_node(disconnect=disconnects)
l1.rpc.connect('localhost', l2.info['port'], l2.info['id']) l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
@ -479,8 +475,8 @@ class LightningDTests(BaseLightningDTests):
def test_permfail_htlc_out(self): def test_permfail_htlc_out(self):
# Test case where we fail with unsettled outgoing HTLC. # Test case where we fail with unsettled outgoing HTLC.
disconnects = ['+WIRE_REVOKE_AND_ACK', 'permfail'] disconnects = ['+WIRE_REVOKE_AND_ACK', 'permfail']
l1 = self.node_factory.get_node(legacy=False) l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node(legacy=False, disconnect=disconnects) l2 = self.node_factory.get_node(disconnect=disconnects)
l1.rpc.connect('localhost', l2.info['port'], l2.info['id']) l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
self.fund_channel(l2, l1, 10**6) self.fund_channel(l2, l1, 10**6)
@ -579,9 +575,9 @@ class LightningDTests(BaseLightningDTests):
# Connect two peers, reconnect and then see if we resume the # Connect two peers, reconnect and then see if we resume the
# gossip. # gossip.
disconnects = ['-WIRE_CHANNEL_ANNOUNCEMENT'] disconnects = ['-WIRE_CHANNEL_ANNOUNCEMENT']
l1 = self.node_factory.get_node(legacy=False, disconnect=disconnects) l1 = self.node_factory.get_node(disconnect=disconnects)
l2 = self.node_factory.get_node(legacy=False) l2 = self.node_factory.get_node()
l3 = self.node_factory.get_node(legacy=False) l3 = self.node_factory.get_node()
l1.rpc.connect('localhost', l2.info['port'], l2.info['id']) l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
l1.openchannel(l2, 20000) l1.openchannel(l2, 20000)
@ -594,7 +590,7 @@ class LightningDTests(BaseLightningDTests):
wait_for(lambda: len(n.rpc.getchannels()['channels']) == 4) wait_for(lambda: len(n.rpc.getchannels()['channels']) == 4)
def test_routing_gossip(self): def test_routing_gossip(self):
nodes = [self.node_factory.get_node(legacy=False) for _ in range(5)] nodes = [self.node_factory.get_node() for _ in range(5)]
l1 = nodes[0] l1 = nodes[0]
l5 = nodes[4] l5 = nodes[4]
@ -638,7 +634,7 @@ class LightningDTests(BaseLightningDTests):
def test_forward(self): def test_forward(self):
# Connect 1 -> 2 -> 3. # Connect 1 -> 2 -> 3.
l1,l2 = self.connect() l1,l2 = self.connect()
l3 = self.node_factory.get_node(legacy=False) l3 = self.node_factory.get_node()
ret = l2.rpc.connect('localhost', l3.info['port'], l3.info['id']) ret = l2.rpc.connect('localhost', l3.info['port'], l3.info['id'])
assert ret['id'] == l3.info['id'] assert ret['id'] == l3.info['id']
@ -698,8 +694,8 @@ class LightningDTests(BaseLightningDTests):
disconnects = ['-WIRE_INIT', disconnects = ['-WIRE_INIT',
'@WIRE_INIT', '@WIRE_INIT',
'+WIRE_INIT'] '+WIRE_INIT']
l1 = self.node_factory.get_node(legacy=False, disconnect=disconnects) l1 = self.node_factory.get_node(disconnect=disconnects)
l2 = self.node_factory.get_node(legacy=False) l2 = self.node_factory.get_node()
for d in disconnects: for d in disconnects:
self.assertRaises(ValueError, l1.rpc.connect, self.assertRaises(ValueError, l1.rpc.connect,
'localhost', l2.info['port'], l2.info['id']) 'localhost', l2.info['port'], l2.info['id'])
@ -715,8 +711,8 @@ class LightningDTests(BaseLightningDTests):
'+WIRE_OPEN_CHANNEL', '+WIRE_OPEN_CHANNEL',
'-WIRE_FUNDING_CREATED', '-WIRE_FUNDING_CREATED',
'@WIRE_FUNDING_CREATED'] '@WIRE_FUNDING_CREATED']
l1 = self.node_factory.get_node(legacy=False, disconnect=disconnects) l1 = self.node_factory.get_node(disconnect=disconnects)
l2 = self.node_factory.get_node(legacy=False) l2 = self.node_factory.get_node()
addr = l1.rpc.newaddr()['address'] addr = l1.rpc.newaddr()['address']
txid = l1.bitcoin.rpc.sendtoaddress(addr, 20000 / 10**6) txid = l1.bitcoin.rpc.sendtoaddress(addr, 20000 / 10**6)
@ -733,8 +729,8 @@ class LightningDTests(BaseLightningDTests):
disconnects = ['-WIRE_ACCEPT_CHANNEL', disconnects = ['-WIRE_ACCEPT_CHANNEL',
'@WIRE_ACCEPT_CHANNEL', '@WIRE_ACCEPT_CHANNEL',
'+WIRE_ACCEPT_CHANNEL'] '+WIRE_ACCEPT_CHANNEL']
l1 = self.node_factory.get_node(legacy=False) l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node(legacy=False, disconnect=disconnects) l2 = self.node_factory.get_node(disconnect=disconnects)
addr = l1.rpc.newaddr()['address'] addr = l1.rpc.newaddr()['address']
txid = l1.bitcoin.rpc.sendtoaddress(addr, 20000 / 10**6) txid = l1.bitcoin.rpc.sendtoaddress(addr, 20000 / 10**6)
@ -750,8 +746,8 @@ class LightningDTests(BaseLightningDTests):
# Now, these are the corner cases. Fundee sends funding_signed, # Now, these are the corner cases. Fundee sends funding_signed,
# but funder doesn't receive it. # but funder doesn't receive it.
disconnects = ['@WIRE_FUNDING_SIGNED'] disconnects = ['@WIRE_FUNDING_SIGNED']
l1 = self.node_factory.get_node(legacy=False) l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node(legacy=False, disconnect=disconnects) l2 = self.node_factory.get_node(disconnect=disconnects)
addr = l1.rpc.newaddr()['address'] addr = l1.rpc.newaddr()['address']
txid = l1.bitcoin.rpc.sendtoaddress(addr, 20000 / 10**6) txid = l1.bitcoin.rpc.sendtoaddress(addr, 20000 / 10**6)
@ -768,8 +764,8 @@ class LightningDTests(BaseLightningDTests):
def test_reconnect_signed(self): def test_reconnect_signed(self):
# This will fail *after* both sides consider channel opening. # This will fail *after* both sides consider channel opening.
disconnects = ['+WIRE_FUNDING_SIGNED'] disconnects = ['+WIRE_FUNDING_SIGNED']
l1 = self.node_factory.get_node(legacy=False) l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node(legacy=False, disconnect=disconnects) l2 = self.node_factory.get_node(disconnect=disconnects)
addr = l1.rpc.newaddr()['address'] addr = l1.rpc.newaddr()['address']
txid = l1.bitcoin.rpc.sendtoaddress(addr, 20000 / 10**6) txid = l1.bitcoin.rpc.sendtoaddress(addr, 20000 / 10**6)
@ -799,8 +795,8 @@ class LightningDTests(BaseLightningDTests):
disconnects = ['-WIRE_FUNDING_LOCKED', disconnects = ['-WIRE_FUNDING_LOCKED',
'@WIRE_FUNDING_LOCKED', '@WIRE_FUNDING_LOCKED',
'+WIRE_FUNDING_LOCKED'] '+WIRE_FUNDING_LOCKED']
l1 = self.node_factory.get_node(legacy=False, disconnect=disconnects) l1 = self.node_factory.get_node(disconnect=disconnects)
l2 = self.node_factory.get_node(legacy=False) l2 = self.node_factory.get_node()
ret = l1.rpc.connect('localhost', l2.info['port'], l2.info['id']) ret = l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
@ -816,8 +812,8 @@ class LightningDTests(BaseLightningDTests):
'-WIRE_REVOKE_AND_ACK', '-WIRE_REVOKE_AND_ACK',
'@WIRE_REVOKE_AND_ACK', '@WIRE_REVOKE_AND_ACK',
'+WIRE_REVOKE_AND_ACK'] '+WIRE_REVOKE_AND_ACK']
l1 = self.node_factory.get_node(legacy=False, disconnect=disconnects) l1 = self.node_factory.get_node(disconnect=disconnects)
l2 = self.node_factory.get_node(legacy=False) l2 = self.node_factory.get_node()
ret = l1.rpc.connect('localhost', l2.info['port'], l2.info['id']) ret = l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
@ -857,8 +853,8 @@ class LightningDTests(BaseLightningDTests):
'-WIRE_REVOKE_AND_ACK', '-WIRE_REVOKE_AND_ACK',
'@WIRE_REVOKE_AND_ACK', '@WIRE_REVOKE_AND_ACK',
'+WIRE_REVOKE_AND_ACK'] '+WIRE_REVOKE_AND_ACK']
l1 = self.node_factory.get_node(legacy=False) l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node(legacy=False, disconnect=disconnects) l2 = self.node_factory.get_node(disconnect=disconnects)
ret = l1.rpc.connect('localhost', l2.info['port'], l2.info['id']) ret = l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
@ -883,8 +879,8 @@ class LightningDTests(BaseLightningDTests):
'-WIRE_REVOKE_AND_ACK', '-WIRE_REVOKE_AND_ACK',
'@WIRE_REVOKE_AND_ACK', '@WIRE_REVOKE_AND_ACK',
'+WIRE_REVOKE_AND_ACK'] '+WIRE_REVOKE_AND_ACK']
l1 = self.node_factory.get_node(legacy=False) l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node(legacy=False, disconnect=disconnects) l2 = self.node_factory.get_node(disconnect=disconnects)
ret = l1.rpc.connect('localhost', l2.info['port'], l2.info['id']) ret = l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
@ -903,8 +899,8 @@ class LightningDTests(BaseLightningDTests):
disconnects = ['-WIRE_SHUTDOWN', disconnects = ['-WIRE_SHUTDOWN',
'@WIRE_SHUTDOWN', '@WIRE_SHUTDOWN',
'+WIRE_SHUTDOWN'] '+WIRE_SHUTDOWN']
l1 = self.node_factory.get_node(legacy=False, disconnect=disconnects) l1 = self.node_factory.get_node(disconnect=disconnects)
l2 = self.node_factory.get_node(legacy=False) l2 = self.node_factory.get_node()
l1.rpc.connect('localhost', l2.info['port'], l2.info['id']) l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
@ -930,8 +926,8 @@ class LightningDTests(BaseLightningDTests):
disconnects = ['-WIRE_CLOSING_SIGNED', disconnects = ['-WIRE_CLOSING_SIGNED',
'@WIRE_CLOSING_SIGNED', '@WIRE_CLOSING_SIGNED',
'+WIRE_CLOSING_SIGNED'] '+WIRE_CLOSING_SIGNED']
l1 = self.node_factory.get_node(legacy=False, disconnect=disconnects) l1 = self.node_factory.get_node(disconnect=disconnects)
l2 = self.node_factory.get_node(legacy=False) l2 = self.node_factory.get_node()
l1.rpc.connect('localhost', l2.info['port'], l2.info['id']) l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
@ -955,7 +951,7 @@ class LightningDTests(BaseLightningDTests):
def test_json_addfunds(self): def test_json_addfunds(self):
sat = 10**6 sat = 10**6
l1 = self.node_factory.get_node(legacy=False) l1 = self.node_factory.get_node()
addr = l1.rpc.newaddr()['address'] addr = l1.rpc.newaddr()['address']
txid = l1.bitcoin.rpc.sendtoaddress(addr, 0.01) txid = l1.bitcoin.rpc.sendtoaddress(addr, 0.01)
tx = l1.bitcoin.rpc.getrawtransaction(txid) tx = l1.bitcoin.rpc.getrawtransaction(txid)
@ -968,7 +964,7 @@ class LightningDTests(BaseLightningDTests):
def test_withdraw(self): def test_withdraw(self):
amount = 1000000 amount = 1000000
l1 = self.node_factory.get_node(legacy=False) l1 = self.node_factory.get_node()
addr = l1.rpc.newaddr()['address'] addr = l1.rpc.newaddr()['address']
@ -1052,60 +1048,5 @@ class LightningDTests(BaseLightningDTests):
l1.daemon.start() l1.daemon.start()
assert l1.rpc.getpeers()['peers'][0]['msatoshi_to_us'] == 99980000 assert l1.rpc.getpeers()['peers'][0]['msatoshi_to_us'] == 99980000
class LegacyLightningDTests(BaseLightningDTests):
def test_connect(self):
l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node()
l1.connect(l2, 0.01, async=False)
def test_successful_payment(self):
l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node()
bitcoind = l1.bitcoin
capacity = 0.01 * 10**8 * 10**3
htlc_amount = 10000
l1.connect(l2, 0.01)
invoice = l2.rpc.invoice(htlc_amount, "successful_payment")
# TODO(cdecker) Assert that we have an invoice
rhash = invoice['rhash']
assert len(rhash) == 64
route = l1.rpc.getroute(l2.info['id'], htlc_amount, 1)
assert len(route) == 1
assert route[0] == {'msatoshi': htlc_amount, 'id': l2.info['id'], 'delay': 6}
receipt = l1.rpc.sendpay(route, invoice['rhash'])
assert sha256(unhexlify(receipt['preimage'])).hexdigest() == rhash
# Now go for the combined RPC call
invoice = l2.rpc.invoice(100, "one_shot_payment")
l1.rpc.pay(l2.info['id'], 100, invoice['rhash'])
def test_multihop_payment(self):
nodes = [self.node_factory.get_node() for _ in range(5)]
for i in range(len(nodes)-1):
nodes[i].connect(nodes[i+1], 0.01)
htlc_amount = 10000
# Manually add channel l2 -> l3 to l1 so that it can compute the route
for i in range(len(nodes)-1):
nodes[0].rpc.dev_add_route(nodes[i].info['id'], nodes[i+1].info['id'], 1, 1, 6, 6)
#l1.rpc.dev_add_route(l2.info['id'], l3.info['id'], 1, 1, 6, 6)
sync_blockheight(nodes)
invoice = nodes[-1].rpc.invoice(htlc_amount, "multihop_payment")
route = nodes[0].rpc.getroute(nodes[-1].info['id'], htlc_amount, 1)
receipt = nodes[0].rpc.sendpay(route, invoice['rhash'])
nodes[-1].daemon.wait_for_log("STATE_NORMAL_COMMITTING => STATE_NORMAL")
nodes[0].daemon.wait_for_log("STATE_NORMAL_COMMITTING => STATE_NORMAL")
if __name__ == '__main__': if __name__ == '__main__':
unittest.main(verbosity=2) unittest.main(verbosity=2)

13
tests/utils.py

@ -235,19 +235,6 @@ class LightningD(TailableProc):
TailableProc.stop(self) TailableProc.stop(self)
logging.info("LightningD stopped") logging.info("LightningD stopped")
class LegacyLightningD(LightningD):
def __init__(self, *args, **kwargs):
LightningD.__init__(self, *args, **kwargs)
self.cmd_line[0] = 'daemon/lightningd'
# Filter out non-legacy options
self.cmd_line = [c for c in self.cmd_line if '--network' not in c and '--dev-broadcast-interval' not in c]
def start(self):
TailableProc.start(self)
self.wait_for_log("Hello world!")
logging.info("LightningD started")
class LightningNode(object): class LightningNode(object):
def __init__(self, daemon, rpc, btc, executor): def __init__(self, daemon, rpc, btc, executor):
self.rpc = rpc self.rpc = rpc

3
type_to_string.c

@ -1,10 +1,7 @@
#include "bitcoin/locktime.h" #include "bitcoin/locktime.h"
#include "bitcoin/pubkey.h" #include "bitcoin/pubkey.h"
#include "bitcoin/tx.h" #include "bitcoin/tx.h"
#include "daemon/channel.h"
#include "daemon/htlc.h" #include "daemon/htlc.h"
#include "daemon/lightningd.h"
#include "daemon/peer.h"
#include "protobuf_convert.h" #include "protobuf_convert.h"
#include "type_to_string.h" #include "type_to_string.h"
#include "utils.h" #include "utils.h"

Loading…
Cancel
Save