mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 21:35:11 +01:00
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>
This commit is contained in:
parent
58a62e782d
commit
5bc22f0368
@ -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
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))
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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 */
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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
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
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);
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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…
Reference in New Issue
Block a user