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
env:
- NOVALGRIND=1 NO_VALGRIND=0
- NOVALGRIND=0 NO_VALGRIND=1
- NOVALGRIND=1
- NOVALGRIND=0
# Trusty (aka 14.04) is way way too old, so run in docker...
script:
- 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 -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

4
INSTALL.md

@ -51,7 +51,7 @@ make
Running lightning:
```
bitcoind &
./daemon/lightningd &
./lightningd/lightningd &
./daemon/lightning-cli help
```
**Note**: You may need to include `testnet=1` in `bitcoin.conf`
@ -85,6 +85,6 @@ Running lightning:
```
bitcoind
export LD_LIBRARY_PATH=/usr/local/lib
./daemon/lightningd
./lightningd/lightningd
./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)
$(PROGRAMS): CFLAGS+=-I.
default: $(PROGRAMS) doc-all daemon-all
default: $(PROGRAMS) doc-all
include doc/Makefile
include bitcoin/Makefile
@ -242,7 +242,7 @@ test-protocol: test/test_protocol
check: test-protocol
$(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
# 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
# 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 [ 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

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])
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__":
l1 = LightningRpc("/tmp/lightning1/lightning-rpc")

62
daemon/Makefile

@ -8,7 +8,7 @@ LC_CTYPE=C
daemon-wrongdir:
$(MAKE) -C .. daemon-all
daemon-all: daemon/lightningd daemon/lightning-cli
daemon-all: daemon/lightning-cli
DAEMON_LIB_SRC := \
daemon/configdir.c \
@ -21,35 +21,16 @@ DAEMON_SRC := \
daemon/bitcoind.c \
daemon/broadcast.c \
daemon/chaintopology.c \
daemon/channel.c \
daemon/commit_tx.c \
daemon/cryptopkt.c \
daemon/db.c \
daemon/dns.c \
daemon/failure.c \
daemon/feechange.c \
daemon/htlc.c \
daemon/htlc_state.c \
daemon/invoice.c \
daemon/irc_announce.c \
daemon/jsonrpc.c \
daemon/lightningd.c \
daemon/netaddr.c \
daemon/options.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/routingrpc.c \
daemon/secrets.c \
daemon/sphinx.c \
daemon/timeout.c \
daemon/wallet.c \
daemon/watch.c \
daemon/names.c \
irc.c
DAEMON_OBJS := $(DAEMON_SRC:.c=.o)
@ -61,50 +42,28 @@ DAEMON_JSMN_OBJS := daemon/jsmn.o
DAEMON_JSMN_HEADERS := daemon/jsmn/jsmn.h
DAEMON_GEN_HEADERS := \
daemon/gen_feechange_state_names.h \
daemon/gen_htlc_state_names.h \
daemon/gen_pkt_names.h \
daemon/gen_state_names.h
daemon/gen_htlc_state_names.h
DAEMON_HEADERS := \
daemon/bitcoind.h \
daemon/broadcast.h \
daemon/chaintopology.h \
daemon/channel.h \
daemon/commit_tx.h \
daemon/configdir.h \
daemon/cryptopkt.h \
daemon/db.h \
daemon/dns.h \
daemon/failure.h \
daemon/feechange.h \
daemon/feechange_state.h \
daemon/htlc.h \
daemon/htlc_state.h \
daemon/invoice.h \
daemon/irc_announce.h \
daemon/json.h \
daemon/jsonrpc.h \
daemon/lightningd.h \
daemon/log.h \
daemon/names.h \
daemon/netaddr.h \
daemon/opt_time.h \
daemon/options.h \
daemon/output_to_htlc.h \
daemon/p2p_announce.h \
daemon/packets.h \
daemon/pay.h \
daemon/peer.h \
daemon/peer_internal.h \
daemon/pseudorand.h \
daemon/routing.h \
daemon/secrets.h \
daemon/sphinx.h \
daemon/state.h \
daemon/state_types.h \
daemon/timeout.h \
daemon/wallet.h \
daemon/watch.h
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
(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_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_CLI_SRC:%=check-src-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/%)
@ -152,17 +106,9 @@ daemon/jsmn/jsmn.c: daemon/jsmn/jsmn.h
daemon/jsmn.o: daemon/jsmn/jsmn.c
$(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-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:
include daemon/test/Makefile

1
daemon/chaintopology.c

@ -5,7 +5,6 @@
#include "jsonrpc.h"
#include "lightningd.h"
#include "log.h"
#include "peer.h"
#include "timeout.h"
#include "utils.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 "lightningd.h"
#include "log.h"
#include "peer.h"
#include "netaddr.h"
#include <assert.h>
#include <ccan/err/err.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);
}
/* 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)
{
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 "lightningd.h"
#include "log.h"
#include "peer.h"
#include "version.h"
#include <ccan/array_size/array_size.h>
#include <ccan/err/err.h>
@ -231,6 +230,9 @@ static const struct 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,
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 "lightningd.h"
#include "log.h"
#include "peer.h"
#include "pseudorand.h"
#include "timeout.h"
#include "watch.h"
@ -160,6 +159,9 @@ struct txowatch *watch_txo_(const tal_t *ctx,
return w;
}
/* UNIFICATION FIXME */
void peer_debug(struct peer *peer, const char *fmt, ...);
/* Returns true if we fired a callback */
static bool txw_fire(struct chain_topology *topo,
struct txwatch *txw,

151
tests/test_lightningd.py

@ -2,7 +2,7 @@ from binascii import hexlify, unhexlify
from concurrent import futures
from decimal import Decimal
from hashlib import sha256
from lightning import LightningRpc, LegacyLightningRpc
from lightning import LightningRpc
import copy
import json
@ -86,7 +86,7 @@ class NodeFactory(object):
self.nodes = []
self.executor = executor
def get_node(self, legacy=True, disconnect=None):
def get_node(self, disconnect=None):
node_id = self.next_id
self.next_id += 1
@ -95,17 +95,13 @@ class NodeFactory(object):
socket_path = os.path.join(lightning_dir, "lightning-rpc").format(node_id)
port = 16330+node_id
if legacy:
daemon = utils.LegacyLightningD(lightning_dir, bitcoind.bitcoin_dir, port=port)
rpc = LegacyLightningRpc(socket_path, self.executor)
else:
daemon = utils.LightningD(lightning_dir, bitcoind.bitcoin_dir, port=port)
# If we have a disconnect string, dump it to a file for daemon.
if disconnect:
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)
daemon = utils.LightningD(lightning_dir, bitcoind.bitcoin_dir, port=port)
# If we have a disconnect string, dump it to a file for daemon.
if disconnect:
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)
self.nodes.append(node)
@ -170,8 +166,8 @@ class BaseLightningDTests(unittest.TestCase):
class LightningDTests(BaseLightningDTests):
def connect(self):
l1 = self.node_factory.get_node(legacy=False)
l2 = self.node_factory.get_node(legacy=False)
l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node()
ret = l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
assert ret['id'] == l2.info['id']
@ -401,8 +397,8 @@ class LightningDTests(BaseLightningDTests):
def test_permfail_new_commit(self):
# Test case where we have two possible commits: it will use new one.
disconnects = ['-WIRE_REVOKE_AND_ACK', 'permfail']
l1 = self.node_factory.get_node(legacy=False)
l2 = self.node_factory.get_node(legacy=False, disconnect=disconnects)
l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node(disconnect=disconnects)
l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
self.fund_channel(l1, l2, 10**6)
@ -440,8 +436,8 @@ class LightningDTests(BaseLightningDTests):
def test_permfail_htlc_in(self):
# Test case where we fail with unsettled incoming HTLC.
disconnects = ['-WIRE_UPDATE_FULFILL_HTLC', 'permfail']
l1 = self.node_factory.get_node(legacy=False)
l2 = self.node_factory.get_node(legacy=False, disconnect=disconnects)
l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node(disconnect=disconnects)
l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
self.fund_channel(l1, l2, 10**6)
@ -479,8 +475,8 @@ class LightningDTests(BaseLightningDTests):
def test_permfail_htlc_out(self):
# Test case where we fail with unsettled outgoing HTLC.
disconnects = ['+WIRE_REVOKE_AND_ACK', 'permfail']
l1 = self.node_factory.get_node(legacy=False)
l2 = self.node_factory.get_node(legacy=False, disconnect=disconnects)
l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node(disconnect=disconnects)
l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
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
# gossip.
disconnects = ['-WIRE_CHANNEL_ANNOUNCEMENT']
l1 = self.node_factory.get_node(legacy=False, disconnect=disconnects)
l2 = self.node_factory.get_node(legacy=False)
l3 = self.node_factory.get_node(legacy=False)
l1 = self.node_factory.get_node(disconnect=disconnects)
l2 = self.node_factory.get_node()
l3 = self.node_factory.get_node()
l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
l1.openchannel(l2, 20000)
@ -594,7 +590,7 @@ class LightningDTests(BaseLightningDTests):
wait_for(lambda: len(n.rpc.getchannels()['channels']) == 4)
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]
l5 = nodes[4]
@ -638,7 +634,7 @@ class LightningDTests(BaseLightningDTests):
def test_forward(self):
# Connect 1 -> 2 -> 3.
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'])
assert ret['id'] == l3.info['id']
@ -698,8 +694,8 @@ class LightningDTests(BaseLightningDTests):
disconnects = ['-WIRE_INIT',
'@WIRE_INIT',
'+WIRE_INIT']
l1 = self.node_factory.get_node(legacy=False, disconnect=disconnects)
l2 = self.node_factory.get_node(legacy=False)
l1 = self.node_factory.get_node(disconnect=disconnects)
l2 = self.node_factory.get_node()
for d in disconnects:
self.assertRaises(ValueError, l1.rpc.connect,
'localhost', l2.info['port'], l2.info['id'])
@ -715,8 +711,8 @@ class LightningDTests(BaseLightningDTests):
'+WIRE_OPEN_CHANNEL',
'-WIRE_FUNDING_CREATED',
'@WIRE_FUNDING_CREATED']
l1 = self.node_factory.get_node(legacy=False, disconnect=disconnects)
l2 = self.node_factory.get_node(legacy=False)
l1 = self.node_factory.get_node(disconnect=disconnects)
l2 = self.node_factory.get_node()
addr = l1.rpc.newaddr()['address']
txid = l1.bitcoin.rpc.sendtoaddress(addr, 20000 / 10**6)
@ -733,8 +729,8 @@ class LightningDTests(BaseLightningDTests):
disconnects = ['-WIRE_ACCEPT_CHANNEL',
'@WIRE_ACCEPT_CHANNEL',
'+WIRE_ACCEPT_CHANNEL']
l1 = self.node_factory.get_node(legacy=False)
l2 = self.node_factory.get_node(legacy=False, disconnect=disconnects)
l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node(disconnect=disconnects)
addr = l1.rpc.newaddr()['address']
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,
# but funder doesn't receive it.
disconnects = ['@WIRE_FUNDING_SIGNED']
l1 = self.node_factory.get_node(legacy=False)
l2 = self.node_factory.get_node(legacy=False, disconnect=disconnects)
l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node(disconnect=disconnects)
addr = l1.rpc.newaddr()['address']
txid = l1.bitcoin.rpc.sendtoaddress(addr, 20000 / 10**6)
@ -768,8 +764,8 @@ class LightningDTests(BaseLightningDTests):
def test_reconnect_signed(self):
# This will fail *after* both sides consider channel opening.
disconnects = ['+WIRE_FUNDING_SIGNED']
l1 = self.node_factory.get_node(legacy=False)
l2 = self.node_factory.get_node(legacy=False, disconnect=disconnects)
l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node(disconnect=disconnects)
addr = l1.rpc.newaddr()['address']
txid = l1.bitcoin.rpc.sendtoaddress(addr, 20000 / 10**6)
@ -799,8 +795,8 @@ class LightningDTests(BaseLightningDTests):
disconnects = ['-WIRE_FUNDING_LOCKED',
'@WIRE_FUNDING_LOCKED',
'+WIRE_FUNDING_LOCKED']
l1 = self.node_factory.get_node(legacy=False, disconnect=disconnects)
l2 = self.node_factory.get_node(legacy=False)
l1 = self.node_factory.get_node(disconnect=disconnects)
l2 = self.node_factory.get_node()
ret = l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
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']
l1 = self.node_factory.get_node(legacy=False, disconnect=disconnects)
l2 = self.node_factory.get_node(legacy=False)
l1 = self.node_factory.get_node(disconnect=disconnects)
l2 = self.node_factory.get_node()
ret = l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
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']
l1 = self.node_factory.get_node(legacy=False)
l2 = self.node_factory.get_node(legacy=False, disconnect=disconnects)
l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node(disconnect=disconnects)
ret = l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
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']
l1 = self.node_factory.get_node(legacy=False)
l2 = self.node_factory.get_node(legacy=False, disconnect=disconnects)
l1 = self.node_factory.get_node()
l2 = self.node_factory.get_node(disconnect=disconnects)
ret = l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
self.fund_channel(l1, l2, 10**6)
@ -903,8 +899,8 @@ class LightningDTests(BaseLightningDTests):
disconnects = ['-WIRE_SHUTDOWN',
'@WIRE_SHUTDOWN',
'+WIRE_SHUTDOWN']
l1 = self.node_factory.get_node(legacy=False, disconnect=disconnects)
l2 = self.node_factory.get_node(legacy=False)
l1 = self.node_factory.get_node(disconnect=disconnects)
l2 = self.node_factory.get_node()
l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
self.fund_channel(l1, l2, 10**6)
@ -930,8 +926,8 @@ class LightningDTests(BaseLightningDTests):
disconnects = ['-WIRE_CLOSING_SIGNED',
'@WIRE_CLOSING_SIGNED',
'+WIRE_CLOSING_SIGNED']
l1 = self.node_factory.get_node(legacy=False, disconnect=disconnects)
l2 = self.node_factory.get_node(legacy=False)
l1 = self.node_factory.get_node(disconnect=disconnects)
l2 = self.node_factory.get_node()
l1.rpc.connect('localhost', l2.info['port'], l2.info['id'])
self.fund_channel(l1, l2, 10**6)
@ -955,7 +951,7 @@ class LightningDTests(BaseLightningDTests):
def test_json_addfunds(self):
sat = 10**6
l1 = self.node_factory.get_node(legacy=False)
l1 = self.node_factory.get_node()
addr = l1.rpc.newaddr()['address']
txid = l1.bitcoin.rpc.sendtoaddress(addr, 0.01)
tx = l1.bitcoin.rpc.getrawtransaction(txid)
@ -968,7 +964,7 @@ class LightningDTests(BaseLightningDTests):
def test_withdraw(self):
amount = 1000000
l1 = self.node_factory.get_node(legacy=False)
l1 = self.node_factory.get_node()
addr = l1.rpc.newaddr()['address']
@ -1052,60 +1048,5 @@ class LightningDTests(BaseLightningDTests):
l1.daemon.start()
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__':
unittest.main(verbosity=2)

13
tests/utils.py

@ -235,19 +235,6 @@ class LightningD(TailableProc):
TailableProc.stop(self)
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):
def __init__(self, daemon, rpc, btc, executor):
self.rpc = rpc

3
type_to_string.c

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

Loading…
Cancel
Save