mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 23:24:27 +01:00
daemon/lightningd: remove building, and main files
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Christian Decker
parent
5db4e1144b
commit
88bb38f63b
@@ -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
|
||||
|
||||
@@ -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
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
|
||||
|
||||
@@ -1 +1 @@
|
||||
from .lightning import LightningRpc, LegacyLightningRpc
|
||||
from .lightning import LightningRpc
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
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
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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
1980
daemon/db.c
File diff suppressed because it is too large
Load Diff
76
daemon/db.h
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,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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
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
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
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
5294
daemon/peer.c
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
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);
|
||||
}
|
||||
@@ -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
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, ¶ms[0].ephemeralkey, sessionkey) != 1)
|
||||
return NULL;
|
||||
|
||||
if (!create_shared_secret(
|
||||
params[0].secret, &path[0].pubkey, sessionkey))
|
||||
return NULL;
|
||||
|
||||
compute_blinding_factor(
|
||||
¶ms[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(
|
||||
¶ms[i].ephemeralkey,
|
||||
¶ms[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(¶ms[i].secret, &h, sizeof(h));
|
||||
|
||||
compute_blinding_factor(
|
||||
¶ms[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, ¶ms[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
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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
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);
|
||||
@@ -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 */
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user