Browse Source

protocol: increase HTLC precision to 1/1000 satoshi.

This gets truncated for on-chain transactions (thus, rounding may
contribute to fees).

This also means we currently have an upper bound of 0.04 BTC per HTLC;
this can be increased later if required.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 9 years ago
parent
commit
5bc22f0368
  1. 6
      commit_tx.c
  2. 54
      funding.c
  3. 9
      funding.h
  4. 14
      lightning.pb-c.c
  5. 6
      lightning.pb-c.h
  6. 6
      lightning.proto
  7. 10
      pkt.c
  8. 2
      pkt.h
  9. 4
      test-cli/close-channel.c
  10. 4
      test-cli/create-close-tx.c
  11. 14
      test-cli/gather_updates.c
  12. 6
      test-cli/scripts/setup.sh
  13. 2
      test-cli/scripts/test.sh

6
commit_tx.c

@ -38,7 +38,7 @@ static bool add_htlc(struct bitcoin_tx *tx, size_t n,
htlc_abstime, locktime, rhash,
&htlc_rhash));
tx->output[n].script_length = tal_count(tx->output[n].script);
tx->output[n].amount = h->amount;
tx->output[n].amount = h->amount_msat / 1000;
return true;
}
@ -81,14 +81,14 @@ struct bitcoin_tx *create_commit_tx(const tal_t *ctx,
rhash);
tx->output[0].script = scriptpubkey_p2sh(tx, redeemscript);
tx->output[0].script_length = tal_count(tx->output[0].script);
tx->output[0].amount = cstate->a.pay;
tx->output[0].amount = cstate->a.pay_msat / 1000;
/* Second output is a P2SH payment to them. */
tx->output[1].script = scriptpubkey_p2sh(ctx,
bitcoin_redeem_single(ctx,
&theirkey));
tx->output[1].script_length = tal_count(tx->output[1].script);
tx->output[1].amount = cstate->b.pay;
tx->output[1].amount = cstate->b.pay_msat / 1000;
/* First two outputs done, now for the HTLCs. */
total = tx->output[0].amount + tx->output[1].amount;

54
funding.c

@ -11,7 +11,7 @@ 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)
{
/* Funder gets 1 satsoshi rounding benefit! */
/* Funder gets 1 millisatsoshi rounding benefit! */
*non_funder_fee = fee - fee / 2;
if (*non_funder < *non_funder_fee) {
@ -37,70 +37,71 @@ static bool subtract_fees(uint64_t *funder, uint64_t *non_funder,
return true;
}
static uint64_t htlcs_total(UpdateAddHtlc *const *htlcs)
/* Total, in millisatoshi. */
static uint32_t htlcs_total(UpdateAddHtlc *const *htlcs)
{
size_t i, n = tal_count(htlcs);
uint64_t total = 0;
uint32_t total = 0;
for (i = 0; i < n; i++)
total += htlcs[i]->amount;
total += htlcs[i]->amount_msat;
return total;
}
bool funding_delta(const OpenChannel *oa,
const OpenChannel *ob,
const OpenAnchor *anchor,
int64_t delta_a,
int64_t htlc,
int64_t delta_a_msat,
int64_t htlc_msat,
struct channel_oneside *a_side,
struct channel_oneside *b_side)
{
uint64_t a, b, a_fee, b_fee;
int64_t delta_b;
int64_t delta_b_msat;
uint64_t fee;
bool got_fees;
a = a_side->pay + a_side->fee;
b = b_side->pay + b_side->fee;
fee = a_side->fee + b_side->fee;
a = a_side->pay_msat + a_side->fee_msat;
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);
== anchor->amount * 1000);
/* Only one can be funder. */
if (is_funder(oa) == is_funder(ob))
return false;
/* B gets whatever A gives. */
delta_b = -delta_a;
delta_b_msat = -delta_a_msat;
/* A also pays for the htlc (if any). */
delta_a -= htlc;
delta_a_msat -= htlc_msat;
/* Transferring more than we have? */
if (delta_b < 0 && -delta_b > b)
if (delta_b_msat < 0 && -delta_b_msat > b)
return false;
if (delta_a < 0 && -delta_a > a)
if (delta_a_msat < 0 && -delta_a_msat > a)
return false;
/* Adjust amounts. */
a += delta_a;
b += delta_b;
a += delta_a_msat;
b += delta_b_msat;
/* Take off fee from both parties if possible. */
if (is_funder(oa))
got_fees = subtract_fees(&a, &b, &a_fee, &b_fee,
delta_b < 0, fee);
delta_b_msat < 0, fee);
else
got_fees = subtract_fees(&b, &a, &b_fee, &a_fee,
delta_a < 0, fee);
delta_a_msat < 0, fee);
if (!got_fees)
return false;
/* Now we know we're succeeding, update caller's state */
a_side->pay = a;
b_side->pay = b;
a_side->fee = a_fee;
b_side->fee = b_fee;
a_side->pay_msat = a;
b_side->pay_msat = b;
a_side->fee_msat = a_fee;
b_side->fee_msat = b_fee;
return true;
}
@ -118,9 +119,12 @@ struct channel_state *initial_funding(const tal_t *ctx,
if (fee > anchor->amount)
return tal_free(state);
if (anchor->amount > (1ULL << 32) / 1000)
return tal_free(state);
/* Initially, all goes back to funder. */
state->a.pay = anchor->amount - fee;
state->a.fee = fee;
state->a.pay_msat = anchor->amount * 1000 - fee * 1000;
state->a.fee_msat = fee * 1000;
/* If B (not A) is funder, invert. */
if (is_funder(b))

9
funding.h

@ -6,7 +6,8 @@
#include "lightning.pb-c.h"
struct channel_oneside {
uint64_t pay, fee;
/* Payment and fee is in millisatoshi. */
uint32_t pay_msat, fee_msat;
/* Use tal_count to get the number */
UpdateAddHtlc **htlcs;
};
@ -21,7 +22,7 @@ struct channel_state {
* @a: A's openchannel offer
* @b: B's openchannel offer
* @anchor: The anchor offer (A or B)
* @fee: amount to pay in fees.
* @fee: amount to pay in fees (in satoshi).
*
* Returns state, or NULL if malformed.
*/
@ -36,8 +37,8 @@ struct channel_state *initial_funding(const tal_t *ctx,
* @a: A's openchannel offer
* @b: B's openchannel offer
* @anchor: The anchor offer (A or B)
* @delta_a: How much A changes (-ve => A pay B, +ve => B pays A)
* @htlc: How much A is putting into a HTLC (-ve if htlc is cancelled)
* @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.
*/

14
lightning.pb-c.c

@ -1476,12 +1476,12 @@ static const ProtobufCFieldDescriptor update__field_descriptors[2] =
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"delta",
"delta_msat",
2,
PROTOBUF_C_LABEL_REQUIRED,
PROTOBUF_C_TYPE_SINT64,
0, /* quantifier_offset */
offsetof(Update, delta),
offsetof(Update, delta_msat),
NULL,
NULL,
0, /* flags */
@ -1489,7 +1489,7 @@ static const ProtobufCFieldDescriptor update__field_descriptors[2] =
},
};
static const unsigned update__field_indices_by_name[] = {
1, /* field[1] = delta */
1, /* field[1] = delta_msat */
0, /* field[0] = revocation_hash */
};
static const ProtobufCIntRange update__number_ranges[1 + 1] =
@ -1527,12 +1527,12 @@ static const ProtobufCFieldDescriptor update_add_htlc__field_descriptors[4] =
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"amount",
"amount_msat",
2,
PROTOBUF_C_LABEL_REQUIRED,
PROTOBUF_C_TYPE_UINT64,
PROTOBUF_C_TYPE_UINT32,
0, /* quantifier_offset */
offsetof(UpdateAddHtlc, amount),
offsetof(UpdateAddHtlc, amount_msat),
NULL,
NULL,
0, /* flags */
@ -1564,7 +1564,7 @@ static const ProtobufCFieldDescriptor update_add_htlc__field_descriptors[4] =
},
};
static const unsigned update_add_htlc__field_indices_by_name[] = {
1, /* field[1] = amount */
1, /* field[1] = amount_msat */
3, /* field[3] = expiry */
2, /* field[2] = r_hash */
0, /* field[0] = revocation_hash */

6
lightning.pb-c.h

@ -233,7 +233,7 @@ struct _Update
/*
* Change in current payment to-me (implies reverse to-you).
*/
int64_t delta;
int64_t delta_msat;
};
#define UPDATE__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&update__descriptor) \
@ -251,9 +251,9 @@ struct _UpdateAddHtlc
*/
Sha256Hash *revocation_hash;
/*
* Amount for htlc
* Amount for htlc (millisatoshi)
*/
uint64_t amount;
uint32_t amount_msat;
/*
* Hash for HTLC R value.
*/

6
lightning.proto

@ -99,15 +99,15 @@ message update {
// Hash for which I will supply preimage to revoke this.
required sha256_hash revocation_hash = 1;
// Change in current payment to-me (implies reverse to-you).
required sint64 delta = 2;
required sint64 delta_msat = 2;
}
// Start a new commitment tx to add an HTLC me -> you.
message update_add_htlc {
// Hash for which I will supply preimage to revoke this commitment tx.
required sha256_hash revocation_hash = 1;
// Amount for htlc
required uint64 amount = 2;
// Amount for htlc (millisatoshi)
required uint32 amount_msat = 2;
// Hash for HTLC R value.
required sha256_hash r_hash = 3;
// Time at which HTLC expires (absolute)

10
pkt.c

@ -136,21 +136,25 @@ struct pkt *update_pkt(const tal_t *ctx,
{
Update u = UPDATE__INIT;
u.revocation_hash = sha256_to_proto(ctx, revocation_hash);
u.delta = delta;
u.delta_msat = delta * 1000;
return to_pkt(ctx, PKT__PKT_UPDATE, &u);
}
struct pkt *update_htlc_add_pkt(const tal_t *ctx,
const struct sha256 *revocation_hash,
u64 value,
u32 value,
const struct sha256 *htlc_rhash,
u32 abs_locktime_seconds)
{
UpdateAddHtlc u = UPDATE_ADD_HTLC__INIT;
Locktime l = LOCKTIME__INIT;
/* HTLC total must fit in 32 bits. */
if (value > (1ULL << 32) / 1000)
return NULL;
u.revocation_hash = sha256_to_proto(ctx, revocation_hash);
u.amount = value;
u.amount_msat = value * 1000;
u.r_hash = sha256_to_proto(ctx, htlc_rhash);
l.locktime_case = LOCKTIME__LOCKTIME_SECONDS;
l.seconds = abs_locktime_seconds;

2
pkt.h

@ -100,7 +100,7 @@ struct pkt *update_pkt(const tal_t *ctx,
*/
struct pkt *update_htlc_add_pkt(const tal_t *ctx,
const struct sha256 *revocation_hash,
u64 value,
u32 value,
const struct sha256 *htlc_rhash,
u32 abs_locktime_seconds);

4
test-cli/close-channel.c

@ -88,7 +88,9 @@ int main(int argc, char *argv[])
/* This is what the anchor pays to. */
redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2);
close_tx = create_close_tx(ctx, o1, o2, a, cstate->a.pay, cstate->b.pay);
close_tx = create_close_tx(ctx, o1, o2, a,
cstate->a.pay_msat / 1000,
cstate->b.pay_msat / 1000);
/* Sign it for them. */
sign_tx_input(ctx, close_tx, 0, redeemscript, tal_count(redeemscript),

4
test-cli/create-close-tx.c

@ -66,7 +66,9 @@ int main(int argc, char *argv[])
redeemscript = bitcoin_redeem_2of2(ctx, &pubkey1, &pubkey2);
/* Now create the close tx to spend 2/2 output of anchor. */
close_tx = create_close_tx(ctx, o1, o2, a, cstate->a.pay, cstate->b.pay);
close_tx = create_close_tx(ctx, o1, o2, a,
cstate->a.pay_msat / 1000,
cstate->b.pay_msat / 1000);
/* Signatures well-formed? */
sig1.stype = sig2.stype = SIGHASH_ALL;

14
test-cli/gather_updates.c

@ -144,7 +144,7 @@ struct channel_state *gather_updates(const tal_t *ctx,
sig = pkt->open_commit_sig->sig;
break;
case PKT__PKT_UPDATE_ADD_HTLC:
amount = pkt->update_add_htlc->amount;
amount = pkt->update_add_htlc->amount_msat;
if (received) {
if (!funding_delta(o2, o1, oa, 0, amount,
&cstate->b, &cstate->a))
@ -173,7 +173,7 @@ struct channel_state *gather_updates(const tal_t *ctx,
pkt->update_remove_htlc->r_hash);
if (n == tal_count(cstate->b.htlcs))
errx(1, "Unknown R hash in %s", *argv);
amount = cstate->b.htlcs[n]->amount;
amount = cstate->b.htlcs[n]->amount_msat;
if (!funding_delta(o2, o1, oa, 0, -amount,
&cstate->b, &cstate->a))
errx(1, "Impossible htlc %llu %s",
@ -184,7 +184,7 @@ struct channel_state *gather_updates(const tal_t *ctx,
pkt->update_remove_htlc->r_hash);
if (n == tal_count(cstate->a.htlcs))
errx(1, "Unknown R hash in %s", *argv);
amount = cstate->a.htlcs[n]->amount;
amount = cstate->a.htlcs[n]->amount_msat;
if (!funding_delta(o1, o2, oa, 0, -amount,
&cstate->a, &cstate->b))
errx(1, "Impossible htlc %llu %s",
@ -211,7 +211,7 @@ struct channel_state *gather_updates(const tal_t *ctx,
n = find_htlc(&cstate->a, rh);
if (n == tal_count(cstate->a.htlcs))
errx(1, "Unknown R hash in %s", *argv);
amount = cstate->a.htlcs[n]->amount;
amount = cstate->a.htlcs[n]->amount_msat;
if (!funding_delta(o1, o2, oa, amount, -amount,
&cstate->a, &cstate->b))
errx(1, "Impossible htlc %llu %s",
@ -222,7 +222,7 @@ struct channel_state *gather_updates(const tal_t *ctx,
n = find_htlc(&cstate->b, rh);
if (n == tal_count(cstate->b.htlcs))
errx(1, "Unknown R hash in %s", *argv);
amount = cstate->b.htlcs[n]->amount;
amount = cstate->b.htlcs[n]->amount_msat;
if (!funding_delta(o2, o1, oa, amount, -amount,
&cstate->b, &cstate->a))
errx(1, "Impossible htlc %llu %s",
@ -238,9 +238,9 @@ struct channel_state *gather_updates(const tal_t *ctx,
case PKT__PKT_UPDATE:
if (received)
delta = -pkt->update->delta;
delta = -pkt->update->delta_msat;
else
delta = pkt->update->delta;
delta = pkt->update->delta_msat;
if (!funding_delta(o1, o2, oa, delta, 0,
&cstate->a, &cstate->b))
errx(1, "Impossible funding update %lli %s",

6
test-cli/scripts/setup.sh

@ -24,10 +24,10 @@ done
scripts/generate-block.sh init
A1=`scripts/get-new-address.sh`
TX=`$CLI sendmany "" "{ \"$A1\":10 }"`
TX=`$CLI sendmany "" "{ \"$A1\":0.01 }"`
scripts/generate-block.sh
# Find the inputs number corresponding to that 10 btc out
# Find the inputs number corresponding to that 0.01 btc out
echo "Argument to test.sh:"
for i in $(seq 1 $($CLI listunspent | grep -c txid) ); do scripts/getinput.sh $i | grep -q "$TX.*/1000000000/" && echo -n "$i "; done
for i in $(seq 1 $($CLI listunspent | grep -c txid) ); do scripts/getinput.sh $i | grep -q "$TX.*/1000000/" && echo -n "$i "; done
echo

2
test-cli/scripts/test.sh

@ -53,7 +53,7 @@ A_INPUTNUM=$1
shift
#A_INPUTNUM=4
#B_INPUTNUM=1
A_AMOUNT=100000000
A_AMOUNT=900000
A_CHANGEADDR=`scripts/get-new-address.sh`
A_TMPADDR=`scripts/get-new-address.sh`

Loading…
Cancel
Save