Skip to content

Commit

Permalink
funding: remove protobufs.
Browse files Browse the repository at this point in the history
Use our own structure with the information we need about HTLCs,
and remove protobufs from the API.

The is_funder() helper goes inside gather_updates.h.

Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Jan 21, 2016
1 parent d95d8a9 commit 6d6abd5
Show file tree
Hide file tree
Showing 13 changed files with 188 additions and 106 deletions.
22 changes: 7 additions & 15 deletions commit_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
#include "funding.h"
#include "overflows.h"
#include "permute_tx.h"
#include "protobuf_convert.h"
#include <assert.h>

static bool add_htlc(struct bitcoin_tx *tx, size_t n,
const UpdateAddHtlc *h,
const struct channel_htlc *h,
const struct pubkey *ourkey,
const struct pubkey *theirkey,
const struct sha256 *rhash,
Expand All @@ -23,22 +23,14 @@ static bool add_htlc(struct bitcoin_tx *tx, size_t n,
const struct sha256 *,
const struct sha256 *))
{
struct abs_locktime htlc_abstime;
struct sha256 htlc_rhash;

assert(!tx->output[n].script);

/* This shouldn't happen... */
if (!proto_to_abs_locktime(h->expiry, &htlc_abstime))
return false;

proto_to_sha256(h->r_hash, &htlc_rhash);
tx->output[n].script = scriptpubkey_p2sh(tx,
scriptpubkeyfn(tx, ourkey, theirkey,
&htlc_abstime, locktime, rhash,
&htlc_rhash));
&h->expiry, locktime, rhash,
&h->rhash));
tx->output[n].script_length = tal_count(tx->output[n].script);
tx->output[n].amount = h->amount_msat / 1000;
tx->output[n].amount = h->msatoshis / 1000;
return true;
}

Expand Down Expand Up @@ -88,15 +80,15 @@ struct bitcoin_tx *create_commit_tx(const tal_t *ctx,

/* HTLCs we've sent. */
for (i = 0; i < tal_count(cstate->a.htlcs); i++) {
if (!add_htlc(tx, num, cstate->a.htlcs[i],
if (!add_htlc(tx, num, &cstate->a.htlcs[i],
our_final, their_final,
rhash, their_locktime, scriptpubkey_htlc_send))
return tal_free(tx);
total += tx->output[num++].amount;
}
/* HTLCs we've received. */
for (i = 0; i < tal_count(cstate->b.htlcs); i++) {
if (!add_htlc(tx, num, cstate->b.htlcs[i],
if (!add_htlc(tx, num, &cstate->b.htlcs[i],
our_final, their_final,
rhash, their_locktime, scriptpubkey_htlc_recv))
return tal_free(tx);
Expand Down
79 changes: 46 additions & 33 deletions funding.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@
#include <assert.h>
#include <string.h>

static bool is_funder(const OpenChannel *o)
{
return o->anch == OPEN_CHANNEL__ANCHOR_OFFER__WILL_CREATE_ANCHOR;
}

static bool subtract_fees(uint64_t *funder, uint64_t *non_funder,
uint64_t *funder_fee, uint64_t *non_funder_fee,
bool non_funder_paying, uint64_t fee)
Expand Down Expand Up @@ -38,19 +33,18 @@ static bool subtract_fees(uint64_t *funder, uint64_t *non_funder,
}

/* Total, in millisatoshi. */
static uint32_t htlcs_total(UpdateAddHtlc *const *htlcs)
static uint64_t htlcs_total(const struct channel_htlc *htlcs)
{
size_t i, n = tal_count(htlcs);
uint32_t total = 0;
uint64_t total = 0;

for (i = 0; i < n; i++)
total += htlcs[i]->amount_msat;
total += htlcs[i].msatoshis;
return total;
}

bool funding_delta(const OpenChannel *oa,
const OpenChannel *ob,
const OpenAnchor *anchor,
bool funding_delta(bool a_is_funder,
uint64_t anchor_satoshis,
int64_t delta_a_msat,
int64_t htlc_msat,
struct channel_oneside *a_side,
Expand All @@ -65,11 +59,7 @@ bool funding_delta(const OpenChannel *oa,
b = b_side->pay_msat + b_side->fee_msat;
fee = a_side->fee_msat + b_side->fee_msat;
assert(a + b + htlcs_total(a_side->htlcs) + htlcs_total(b_side->htlcs)
== anchor->amount * 1000);

/* Only one can be funder. */
if (is_funder(oa) == is_funder(ob))
return false;
== anchor_satoshis * 1000);

/* B gets whatever A gives. */
delta_b_msat = -delta_a_msat;
Expand All @@ -87,7 +77,7 @@ bool funding_delta(const OpenChannel *oa,
b += delta_b_msat;

/* Take off fee from both parties if possible. */
if (is_funder(oa))
if (a_is_funder)
got_fees = subtract_fees(&a, &b, &a_fee, &b_fee,
delta_b_msat < 0, fee);
else
Expand All @@ -106,42 +96,41 @@ bool funding_delta(const OpenChannel *oa,
}

struct channel_state *initial_funding(const tal_t *ctx,
const OpenChannel *a,
const OpenChannel *b,
const OpenAnchor *anchor,
bool am_funder,
uint64_t anchor_satoshis,
uint64_t fee)
{
struct channel_state *state = talz(ctx, struct channel_state);

state->a.htlcs = tal_arr(state, UpdateAddHtlc *, 0);
state->b.htlcs = tal_arr(state, UpdateAddHtlc *, 0);
state->a.htlcs = tal_arr(state, struct channel_htlc, 0);
state->b.htlcs = tal_arr(state, struct channel_htlc, 0);

if (fee > anchor->amount)
if (fee > anchor_satoshis)
return tal_free(state);

if (anchor->amount > (1ULL << 32) / 1000)
if (anchor_satoshis > (1ULL << 32) / 1000)
return tal_free(state);

/* Initially, all goes back to funder. */
state->a.pay_msat = anchor->amount * 1000 - fee * 1000;
state->a.pay_msat = anchor_satoshis * 1000 - fee * 1000;
state->a.fee_msat = fee * 1000;

/* If B (not A) is funder, invert. */
if (is_funder(b))
if (!am_funder)
invert_cstate(state);

/* This checks we only have 1 anchor, and is nice code reuse. */
if (!funding_delta(a, b, anchor, 0, 0, &state->a, &state->b))
return tal_free(state);
/* Make sure it checks out. */
assert(funding_delta(am_funder, anchor_satoshis, 0, 0,
&state->a, &state->b));
return state;
}

/* We take the minimum. If one side offers too little, it should be rejected */
uint64_t commit_fee(const OpenChannel *a, const OpenChannel *b)
uint64_t commit_fee(uint64_t a_satoshis, uint64_t b_satoshis)
{
if (a->commitment_fee < b->commitment_fee)
return a->commitment_fee;
return b->commitment_fee;
if (a_satoshis < b_satoshis)
return a_satoshis;
return b_satoshis;
}

void invert_cstate(struct channel_state *cstate)
Expand All @@ -152,3 +141,27 @@ void invert_cstate(struct channel_state *cstate)
cstate->a = cstate->b;
cstate->b = tmp;
}

void funding_add_htlc(struct channel_oneside *creator,
u32 msatoshis, const struct abs_locktime *expiry,
const struct sha256 *rhash)
{
size_t n = tal_count(creator->htlcs);
tal_resize(&creator->htlcs, n+1);

creator->htlcs[n].msatoshis = msatoshis;
creator->htlcs[n].expiry = *expiry;
creator->htlcs[n].rhash = *rhash;
}

struct channel_state *copy_funding(const tal_t *ctx,
const struct channel_state *cstate)
{
struct channel_state *cs = tal_dup(ctx, struct channel_state, cstate);

cs->a.htlcs = tal_dup_arr(cs, struct channel_htlc, cs->a.htlcs,
tal_count(cs->a.htlcs), 0);
cs->b.htlcs = tal_dup_arr(cs, struct channel_htlc, cs->b.htlcs,
tal_count(cs->b.htlcs), 0);
return cs;
}
60 changes: 41 additions & 19 deletions funding.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
#ifndef LIGHTNING_FUNDING_H
#define LIGHTNING_FUNDING_H
#include "config.h"
#include "lightning.pb-c.h"
#include "bitcoin/locktime.h"
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/tal/tal.h>
#include <stdbool.h>

struct channel_htlc {
u64 msatoshis;
struct abs_locktime expiry;
struct sha256 rhash;
};

struct channel_oneside {
/* Payment and fee is in millisatoshi. */
uint32_t pay_msat, fee_msat;
/* Use tal_count to get the number */
UpdateAddHtlc **htlcs;
struct channel_htlc *htlcs;
};

struct channel_state {
Expand All @@ -19,48 +26,63 @@ struct channel_state {
/**
* initial_funding: Given A, B, and anchor, what is initial state?
* @ctx: tal context to allocate return value from.
* @a: A's openchannel offer
* @b: B's openchannel offer
* @anchor: The anchor offer (A or B)
* @am_funder: am I paying for the anchor?
* @anchor_satoshis: The anchor amount.
* @fee: amount to pay in fees (in satoshi).
*
* Returns state, or NULL if malformed.
*/
struct channel_state *initial_funding(const tal_t *ctx,
const OpenChannel *a,
const OpenChannel *b,
const OpenAnchor *anchor,
bool am_funder,
uint64_t anchor_satoshis,
uint64_t fee);

/**
* copy_funding: Make a deep copy of channel_state
* @ctx: tal context to allocate return value from.
* @cstate: state to copy.
*/
struct channel_state *copy_funding(const tal_t *ctx,
const struct channel_state *cstate);

/**
* funding_delta: With this change, what's the new state?
* @a: A's openchannel offer
* @b: B's openchannel offer
* @anchor: The anchor offer (A or B)
* @a_is_funder: is A paying for the anchor?
* @anchor_satoshis: The anchor amount.
* @delta_a: How many millisatoshi A changes (-ve => A pay B, +ve => B pays A)
* @htlc: Millisatoshi A is putting into a HTLC (-ve if htlc is cancelled)
* @a_side: channel a's state to update.
* @b_side: channel b's state to update.
*/
bool funding_delta(const OpenChannel *a,
const OpenChannel *b,
const OpenAnchor *anchor,
int64_t delta_a,
int64_t htlc,
bool funding_delta(bool a_is_funder,
uint64_t anchor_satoshis,
int64_t delta_a_msat,
int64_t htlc_msat,
struct channel_oneside *a_side,
struct channel_oneside *b_side);

/**
* commit_fee: Fee amount for commit tx.
* @a: A's openchannel offer
* @b: B's openchannel offer
* @a_satoshis: A's openchannel->commitment_fee offer
* @b_satoshis: B's openchannel->commitment_fee offer
*/
uint64_t commit_fee(const OpenChannel *a, const OpenChannel *b);
uint64_t commit_fee(uint64_t a_satoshis, uint64_t b_satoshis);

/**
* invert_cstate: Get the other side's state.
* @cstate: the state to invert.
*/
void invert_cstate(struct channel_state *cstate);

/**
* funding_add_htlc: append an HTLC to this side of the channel.
* @creator: channel_state->a or channel_state->b, whichever originated htlc
* @msatoshis: amount in millisatoshi
* @expiry: time it expires
* @rhash: hash of redeem secret
*/
void funding_add_htlc(struct channel_oneside *creator,
u32 msatoshis, const struct abs_locktime *expiry,
const struct sha256 *rhash);

#endif /* LIGHTNING_FUNDING_H */
10 changes: 8 additions & 2 deletions test-cli/check-commit-sig.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "bitcoin/privkey.h"
#include "protobuf_convert.h"
#include "funding.h"
#include "gather_updates.h"
#include "version.h"
#include <unistd.h>

Expand Down Expand Up @@ -70,9 +71,14 @@ int main(int argc, char *argv[])
if (!proto_to_pubkey(o2->commit_key, &pubkey2))
errx(1, "Invalid o2 commit_key");

cstate = initial_funding(ctx, o1, o2, a, commit_fee(o1, o2));
if (is_funder(o1) == is_funder(o2))
errx(1, "Must be exactly one funder");

cstate = initial_funding(ctx, is_funder(o1), a->amount,
commit_fee(o1->commitment_fee,
o2->commitment_fee));
if (!cstate)
errx(1, "Invalid open combination (need 1 anchor offer)");
errx(1, "Invalid open combination (need to cover fees)");

/* Now create our commitment tx. */
proto_to_sha256(o1->revocation_hash, &rhash);
Expand Down
4 changes: 3 additions & 1 deletion test-cli/create-commit-spend-tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ int main(int argc, char *argv[])
errx(1, "Invalid o2 final pubkey");

/* We use this simply to get final revocation hash. */
gather_updates(ctx, o1, o2, a, commit_fee(o1, o2), argv + 7,
gather_updates(ctx, o1, o2, a,
commit_fee(o1->commitment_fee, o2->commitment_fee),
argv + 7,
NULL, &rhash, NULL, NULL);

/* Create redeem script */
Expand Down
5 changes: 4 additions & 1 deletion test-cli/create-commit-tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ int main(int argc, char *argv[])

sig2.stype = SIGHASH_ALL;

cstate = gather_updates(ctx, o1, o2, a, commit_fee(o1, o2), argv + 5,
cstate = gather_updates(ctx, o1, o2, a,
commit_fee(o1->commitment_fee,
o2->commitment_fee),
argv + 5,
NULL, &rhash, NULL, &sig2.sig);

redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2);
Expand Down
Loading

0 comments on commit 6d6abd5

Please sign in to comment.