diff --git a/funding.c b/funding.c index 2f536b13a..496814f55 100644 --- a/funding.c +++ b/funding.c @@ -1,17 +1,18 @@ #include "funding.h" #include -/* FIXME: Fees! */ bool funding_delta(const OpenChannel *a, const OpenChannel *b, const OpenAnchor *anchor, + uint64_t fee, uint64_t *channel_delta, int64_t delta_a_to_b, uint64_t *a_amount, uint64_t *b_amount) { - uint64_t *funder_amount, *non_funder_amount; + uint64_t *funder_amount, *non_funder_amount, new_delta; int64_t delta_to_funder; + uint64_t funder_fee, non_funder_fee; assert(*channel_delta <= anchor->amount); @@ -39,20 +40,58 @@ bool funding_delta(const OpenChannel *a, } else if (-delta_to_funder > anchor->amount - *channel_delta) return false; - *channel_delta -= delta_to_funder; - *funder_amount = anchor->amount - *channel_delta; - *non_funder_amount = *channel_delta; + new_delta = *channel_delta - delta_to_funder; + *funder_amount = anchor->amount - new_delta; + *non_funder_amount = new_delta; + + /* We try to split fee. */ + funder_fee = fee / 2; + /* Funder gets any 1 satoshi rounding benefit! */ + non_funder_fee = fee - funder_fee; + + if (*non_funder_amount < non_funder_fee) { + /* + * This happens initially, as funder has all the money. + * That's OK, but don't let non-funder withdraw if they can't + * cover fee. + */ + if (delta_to_funder > 0) + return false; + + /* Pay everything they can, funder pays rest. */ + non_funder_fee = *non_funder_amount; + funder_fee = fee - non_funder_fee; + } + + /* Funder must always ensure they can pay their share. */ + if (*funder_amount < funder_fee) + return false; + + *funder_amount -= funder_fee; + *non_funder_amount -= non_funder_fee; + + /* Now we know we're succeeding, update caller's channel_delta */ + *channel_delta = new_delta; return true; } bool initial_funding(const OpenChannel *a, const OpenChannel *b, const OpenAnchor *anchor, + uint64_t fee, uint64_t *a_amount, uint64_t *b_amount) { uint64_t channel_delta = 0; - return funding_delta(a, b, anchor, &channel_delta, 0, + return funding_delta(a, b, anchor, fee, &channel_delta, 0, a_amount, b_amount); } + +/* We take the minimum. If one side offers too little, it should be rejected */ +uint64_t commit_fee(const OpenChannel *a, const OpenChannel *b) +{ + if (a->commitment_fee < b->commitment_fee) + return a->commitment_fee; + return b->commitment_fee; +} diff --git a/funding.h b/funding.h index 5c1c0accb..76b1e3782 100644 --- a/funding.h +++ b/funding.h @@ -9,12 +9,14 @@ * @a: A's openchannel offer * @b: B's openchannel offer * @anchor: The anchor offer (A or B) + * @fee: amount to pay in fees. * @a_amount: amount commit tx will output to A. * @b_amount: amount commit tx will output to B. */ bool initial_funding(const OpenChannel *a, const OpenChannel *b, const OpenAnchor *anchor, + uint64_t fee, uint64_t *a_amount, uint64_t *b_amount); @@ -23,6 +25,7 @@ bool initial_funding(const OpenChannel *a, * @a: A's openchannel offer * @b: B's openchannel offer * @anchor: The anchor offer (A or B) + * @fee: amount to pay in fees. * @channel_delta: In/out amount funder pays to non-funder (channel state) * @delta_a_to_b: How much A pays to B (satoshi). * @a_amount: amount commit tx will output to A. @@ -31,9 +34,16 @@ bool initial_funding(const OpenChannel *a, bool funding_delta(const OpenChannel *a, const OpenChannel *b, const OpenAnchor *anchor, + uint64_t fee, uint64_t *channel_delta, int64_t delta_a_to_b, uint64_t *a_amount, uint64_t *b_amount); +/** + * commit_fee: Fee amount for commit tx. + * @a: A's openchannel offer + * @b: B's openchannel offer + */ +uint64_t commit_fee(const OpenChannel *a, const OpenChannel *b); #endif /* LIGHTNING_FUNDING_H */ diff --git a/lightning.pb-c.c b/lightning.pb-c.c index 49c5060e3..8590f7d4b 100644 --- a/lightning.pb-c.c +++ b/lightning.pb-c.c @@ -925,7 +925,7 @@ const ProtobufCEnumDescriptor open_channel__anchor_offer__descriptor = NULL,NULL,NULL,NULL /* reserved[1234] */ }; static const uint32_t open_channel__min_depth__default_value = 0u; -static const ProtobufCFieldDescriptor open_channel__field_descriptors[7] = +static const ProtobufCFieldDescriptor open_channel__field_descriptors[8] = { { "final_key", @@ -1011,10 +1011,23 @@ static const ProtobufCFieldDescriptor open_channel__field_descriptors[7] = 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, + { + "commitment_fee", + 8, + PROTOBUF_C_LABEL_REQUIRED, + PROTOBUF_C_TYPE_UINT64, + 0, /* quantifier_offset */ + offsetof(OpenChannel, commitment_fee), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, }; static const unsigned open_channel__field_indices_by_name[] = { 5, /* field[5] = anch */ 4, /* field[4] = commit_key */ + 7, /* field[7] = commitment_fee */ 0, /* field[0] = final_key */ 2, /* field[2] = locktime_blocks */ 1, /* field[1] = locktime_seconds */ @@ -1024,7 +1037,7 @@ static const unsigned open_channel__field_indices_by_name[] = { static const ProtobufCIntRange open_channel__number_ranges[1 + 1] = { { 1, 0 }, - { 0, 7 } + { 0, 8 } }; const ProtobufCMessageDescriptor open_channel__descriptor = { @@ -1034,7 +1047,7 @@ const ProtobufCMessageDescriptor open_channel__descriptor = "OpenChannel", "", sizeof(OpenChannel), - 7, + 8, open_channel__field_descriptors, open_channel__field_indices_by_name, 1, open_channel__number_ranges, diff --git a/lightning.pb-c.h b/lightning.pb-c.h index 37924b60e..2e1818cbc 100644 --- a/lightning.pb-c.h +++ b/lightning.pb-c.h @@ -127,6 +127,10 @@ struct _OpenChannel */ protobuf_c_boolean has_min_depth; uint32_t min_depth; + /* + * How much fee would I like on commitment tx? + */ + uint64_t commitment_fee; OpenChannel__LocktimeCase locktime_case; union { uint32_t locktime_seconds; @@ -135,7 +139,7 @@ struct _OpenChannel }; #define OPEN_CHANNEL__INIT \ { PROTOBUF_C_MESSAGE_INIT (&open_channel__descriptor) \ - , NULL, NULL, NULL, 0, 0,0u, OPEN_CHANNEL__LOCKTIME__NOT_SET, {} } + , NULL, NULL, NULL, 0, 0,0u, 0, OPEN_CHANNEL__LOCKTIME__NOT_SET, {} } /* diff --git a/lightning.proto b/lightning.proto index c4688af55..1cbef50d0 100644 --- a/lightning.proto +++ b/lightning.proto @@ -58,6 +58,9 @@ message open_channel { // How far must anchor be buried before we consider channel live? optional uint32 min_depth = 7 [ default = 0 ]; + + // How much fee would I like on commitment tx? + required uint64 commitment_fee = 8; } // Whoever is supplying anchor sends this. diff --git a/pkt.c b/pkt.c index eeffef8fd..de6460213 100644 --- a/pkt.c +++ b/pkt.c @@ -37,7 +37,8 @@ struct pkt *open_channel_pkt(const tal_t *ctx, const struct pubkey *final, u32 rel_locktime_seconds, bool offer_anchor, - u32 min_depth) + u32 min_depth, + u64 commitment_fee) { OpenChannel o = OPEN_CHANNEL__INIT; @@ -46,6 +47,7 @@ struct pkt *open_channel_pkt(const tal_t *ctx, o.final_key = pubkey_to_proto(ctx, final); o.locktime_case = OPEN_CHANNEL__LOCKTIME_LOCKTIME_SECONDS; o.locktime_seconds = rel_locktime_seconds; + o.commitment_fee = commitment_fee; if (offer_anchor) o.anch = OPEN_CHANNEL__ANCHOR_OFFER__WILL_CREATE_ANCHOR; else diff --git a/pkt.h b/pkt.h index e081f21df..3e18f2241 100644 --- a/pkt.h +++ b/pkt.h @@ -37,6 +37,7 @@ struct pubkey; * @rel_locktime_seconds: relative seconds for commitment locktime. * @offer_anchor: whether we will offer anchor. * @min_depth: minimum depth to insist on (if non-zero) + * @commitment_fee: fee we would like for commitment txs. */ struct pkt *open_channel_pkt(const tal_t *ctx, const struct sha256 *revocation_hash, @@ -44,7 +45,8 @@ struct pkt *open_channel_pkt(const tal_t *ctx, const struct pubkey *final, u32 rel_locktime_seconds, bool offer_anchor, - u32 min_depth); + u32 min_depth, + u64 commitment_fee); /** * open_anchor_pkt - create an open_anchor message packet diff --git a/test-cli/check-commit-sig.c b/test-cli/check-commit-sig.c index 321214134..19b3ef0d2 100644 --- a/test-cli/check-commit-sig.c +++ b/test-cli/check-commit-sig.c @@ -68,7 +68,8 @@ int main(int argc, char *argv[]) if (!proto_to_pubkey(o2->commit_key, &pubkey2)) errx(1, "Invalid o2 commit_key"); - if (!initial_funding(o1, o2, a, &our_amount, &their_amount)) + if (!initial_funding(o1, o2, a, commit_fee(o1, o2), + &our_amount, &their_amount)) errx(1, "Invalid open combination (need 1 anchor offer)"); /* Now create our commitment tx. */ diff --git a/test-cli/close-channel.c b/test-cli/close-channel.c index 03b1af69c..51fddfa5e 100644 --- a/test-cli/close-channel.c +++ b/test-cli/close-channel.c @@ -57,7 +57,7 @@ int main(int argc, char *argv[]) if (!testnet) errx(1, "Private key '%s' not on testnet!", argv[4]); - gather_updates(o1, o2, a, argv + 5, &our_amount, &their_amount, + gather_updates(o1, o2, a, 0, argv + 5, &our_amount, &their_amount, NULL, NULL, NULL); /* Get pubkeys */ diff --git a/test-cli/create-close-tx.c b/test-cli/create-close-tx.c index 1c2de558c..894c2b8aa 100644 --- a/test-cli/create-close-tx.c +++ b/test-cli/create-close-tx.c @@ -56,7 +56,7 @@ int main(int argc, char *argv[]) errx(1, "Invalid o2 commit_key"); /* Get delta by accumulting all the updates. */ - gather_updates(o1, o2, a, argv + 6, &our_amount, &their_amount, + gather_updates(o1, o2, a, 0, argv + 6, &our_amount, &their_amount, NULL, NULL, NULL); /* This is what the anchor pays to; figure out which output. */ diff --git a/test-cli/create-commit-spend-tx.c b/test-cli/create-commit-spend-tx.c index ca3ea2163..d782b147b 100644 --- a/test-cli/create-commit-spend-tx.c +++ b/test-cli/create-commit-spend-tx.c @@ -19,6 +19,7 @@ #include "find_p2sh_out.h" #include "protobuf_convert.h" #include "test-cli/gather_updates.h" +#include "funding.h" #include int main(int argc, char *argv[]) @@ -81,7 +82,8 @@ int main(int argc, char *argv[]) errx(1, "Invalid o2 final pubkey"); /* We use this simply to get final revocation hash. */ - gather_updates(o1, o2, a, argv + 7, &our_amount, &their_amount, + gather_updates(o1, o2, a, commit_fee(o1, o2), argv + 7, + &our_amount, &their_amount, &rhash, NULL, NULL); /* Create redeem script */ diff --git a/test-cli/create-commit-tx.c b/test-cli/create-commit-tx.c index 7c21c32e4..d52ccfe5d 100644 --- a/test-cli/create-commit-tx.c +++ b/test-cli/create-commit-tx.c @@ -16,6 +16,7 @@ #include "find_p2sh_out.h" #include "protobuf_convert.h" #include "gather_updates.h" +#include "funding.h" #include /* FIXME: this code doesn't work if we're not the ones proposing the delta */ @@ -65,7 +66,8 @@ int main(int argc, char *argv[]) sig2.stype = SIGHASH_ALL; - gather_updates(o1, o2, a, argv + 5, &our_amount, &their_amount, + gather_updates(o1, o2, a, commit_fee(o1, o2), argv + 5, + &our_amount, &their_amount, &rhash, NULL, &sig2.sig); redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2); diff --git a/test-cli/gather_updates.c b/test-cli/gather_updates.c index 2579e6541..00c19a211 100644 --- a/test-cli/gather_updates.c +++ b/test-cli/gather_updates.c @@ -33,7 +33,7 @@ static void get_rhash(const Sha256Hash *rhash, struct sha256 *old, /* Takes complete update history, gets summary of last state. */ uint64_t gather_updates(const OpenChannel *o1, const OpenChannel *o2, - const OpenAnchor *oa, + const OpenAnchor *oa, uint64_t fee, char **argv, uint64_t *our_amount, uint64_t *their_amount, struct sha256 *our_rhash, @@ -46,7 +46,7 @@ uint64_t gather_updates(const OpenChannel *o1, const OpenChannel *o2, struct sha256 old_our_rhash, old_their_rhash; /* Start sanity check. */ - if (!initial_funding(o1, o2, oa, our_amount, their_amount)) + if (!initial_funding(o1, o2, oa, fee, our_amount, their_amount)) errx(1, "Invalid open combination (need 1 anchor offer)"); if (our_rhash) @@ -88,7 +88,7 @@ uint64_t gather_updates(const OpenChannel *o1, const OpenChannel *o2, get_rhash(pkt->update->revocation_hash, &old_our_rhash, our_rhash); } - if (!funding_delta(o1, o2, oa, &cdelta, delta, + if (!funding_delta(o1, o2, oa, fee, &cdelta, delta, our_amount, their_amount)) errx(1, "Impossible funding update %lli %s", (long long)delta, *argv); diff --git a/test-cli/gather_updates.h b/test-cli/gather_updates.h index bfd183dad..57309ffef 100644 --- a/test-cli/gather_updates.h +++ b/test-cli/gather_updates.h @@ -6,7 +6,7 @@ struct signature; struct sha256; uint64_t gather_updates(const OpenChannel *o1, const OpenChannel *o2, - const OpenAnchor *oa, + const OpenAnchor *oa, uint64_t fee, char **argv, uint64_t *our_amount, uint64_t *their_amount, struct sha256 *our_rhash, diff --git a/test-cli/open-channel.c b/test-cli/open-channel.c index fe3959994..4f8edfb2d 100644 --- a/test-cli/open-channel.c +++ b/test-cli/open-channel.c @@ -29,6 +29,7 @@ int main(int argc, char *argv[]) struct pkt *pkt; const tal_t *ctx = tal_arr(NULL, char, 0); unsigned int locktime_seconds, min_confirms; + u64 commit_tx_fee; bool offer_anchor = false; struct pubkey commitkey, finalkey; @@ -38,6 +39,8 @@ int main(int argc, char *argv[]) locktime_seconds = LOCKTIME_MIN + 24 * 60 * 60; /* Zero, unless they set --offer-anchor or --min-anchor-confirms */ min_confirms = 0; + /* We only need this for involuntary close, so make it larger. */ + commit_tx_fee = 100000; opt_register_noarg("--help|-h", opt_usage_and_exit, " \n" @@ -52,6 +55,9 @@ int main(int argc, char *argv[]) opt_register_noarg("--offer-anchor", opt_set_bool, &offer_anchor, "Offer to create anchor transaction"); + opt_register_arg("--commitment-fee=", + opt_set_bits, opt_show_bits, &commit_tx_fee, + "100's of satoshi to pay for commitment"); opt_parse(&argc, argv, opt_log_stderr_exit); @@ -76,7 +82,8 @@ int main(int argc, char *argv[]) revocation_hash.u.u8, sizeof(revocation_hash.u.u8)); pkt = open_channel_pkt(ctx, &revocation_hash, &commitkey, &finalkey, - locktime_seconds, offer_anchor, min_confirms); + locktime_seconds, offer_anchor, min_confirms, + commit_tx_fee); if (!write_all(STDOUT_FILENO, pkt, pkt_totlen(pkt))) err(1, "Writing out packet"); diff --git a/test-cli/open-commit-sig.c b/test-cli/open-commit-sig.c index f3ee3c638..af5f08a74 100644 --- a/test-cli/open-commit-sig.c +++ b/test-cli/open-commit-sig.c @@ -55,7 +55,7 @@ int main(int argc, char *argv[]) errx(1, "Private key '%s' not on testnet!", argv[4]); /* Now create THEIR commitment tx to spend 2/2 output of anchor. */ - if (!initial_funding(o1, o2, a, &to_us, &to_them)) + if (!initial_funding(o1, o2, a, commit_fee(o1, o2), &to_us, &to_them)) errx(1, "Invalid open combination (need 1 anchor offer)"); proto_to_sha256(o2->revocation_hash, &rhash); diff --git a/test-cli/scripts/test.sh b/test-cli/scripts/test.sh index 62a1d450d..ed8337099 100755 --- a/test-cli/scripts/test.sh +++ b/test-cli/scripts/test.sh @@ -114,8 +114,8 @@ B_UPDATE_PKTS="-- +B-commit-sig.pb" $PREFIX ./create-commit-tx A-open.pb B-open.pb A-anchor.pb $A_TMPKEY $A_UPDATE_PKTS > A-commit-0.tx $PREFIX ./create-commit-tx B-open.pb A-open.pb A-anchor.pb $B_TMPKEY $B_UPDATE_PKTS > B-commit-0.tx -# Now, update the channel, so I pay you 500 satoshi. -$PREFIX ./update-channel --to-them=500 $A_SEED 1 > A-update-1.pb +# Now, update the channel, so I pay you 60000 satoshi (covers 50000 fee) +$PREFIX ./update-channel --to-them=60000 $A_SEED 1 > A-update-1.pb A_UPDATE_PKTS="$A_UPDATE_PKTS +A-update-1.pb" B_UPDATE_PKTS="$B_UPDATE_PKTS -A-update-1.pb" diff --git a/test-cli/update-channel-accept.c b/test-cli/update-channel-accept.c index e589b05e4..0120d86e8 100644 --- a/test-cli/update-channel-accept.c +++ b/test-cli/update-channel-accept.c @@ -17,6 +17,7 @@ #include "find_p2sh_out.h" #include "protobuf_convert.h" #include "gather_updates.h" +#include "funding.h" #include int main(int argc, char *argv[]) @@ -60,7 +61,7 @@ int main(int argc, char *argv[]) errx(1, "Private key '%s' not on testnet!", argv[5]); /* Figure out cumulative delta since anchor. */ - num_updates = gather_updates(o1, o2, a, argv + 6, + num_updates = gather_updates(o1, o2, a, commit_fee(o1, o2), argv + 6, &our_amount, &their_amount, NULL, &their_rhash, NULL); diff --git a/test-cli/update-channel-complete.c b/test-cli/update-channel-complete.c index b709ddaa0..3ccc2f5ae 100644 --- a/test-cli/update-channel-complete.c +++ b/test-cli/update-channel-complete.c @@ -56,7 +56,7 @@ int main(int argc, char *argv[]) sig.stype = SIGHASH_ALL; /* This also checks that preimage is correct! */ - num_updates = gather_updates(o1, o2, a, argv + 5, + num_updates = gather_updates(o1, o2, a, commit_fee(o1, o2), argv + 5, &our_amount, &their_amount, &our_rhash, &their_rhash, &sig.sig); if (num_updates < 1) diff --git a/test-cli/update-channel-signature.c b/test-cli/update-channel-signature.c index 08f1a0799..734f14866 100644 --- a/test-cli/update-channel-signature.c +++ b/test-cli/update-channel-signature.c @@ -17,6 +17,7 @@ #include "find_p2sh_out.h" #include "protobuf_convert.h" #include "gather_updates.h" +#include "funding.h" #include int main(int argc, char *argv[]) @@ -62,7 +63,7 @@ int main(int argc, char *argv[]) sig.stype = SIGHASH_ALL; /* Figure out cumulative delta since anchor. */ - num_updates = gather_updates(o1, o2, a, argv + 6, + num_updates = gather_updates(o1, o2, a, commit_fee(o1, o2), argv + 6, &our_amount, &their_amount, &our_rhash, &their_rhash, &sig.sig); if (num_updates < 1)