Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Small fixes: dual-funding #4295

Merged
merged 6 commits into from
Jan 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion common/json_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,11 +290,13 @@ void json_add_tx(struct json_stream *result,

void json_add_psbt(struct json_stream *stream,
const char *fieldname,
const struct wally_psbt *psbt)
const struct wally_psbt *psbt TAKES)
{
const char *psbt_b64;
psbt_b64 = psbt_to_b64(NULL, psbt);
json_add_string(stream, fieldname, take(psbt_b64));
if (taken(psbt))
tal_free(psbt);
}

void json_add_amount_msat_compat(struct json_stream *result,
Expand Down
13 changes: 11 additions & 2 deletions contrib/pyln-client/pyln/client/lightning.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ def to_satoshi(self) -> Decimal:
"""
return Decimal(self.millisatoshis) / 1000

def to_whole_satoshi(self) -> int:
"""
Return an int respresenting the number of satoshis;
rounded up to the nearest satoshi
"""
return (self.millisatoshis + 999) // 1000

def to_btc(self) -> Decimal:
"""
Return a Decimal representing the number of bitcoin.
Expand Down Expand Up @@ -1244,7 +1251,7 @@ def unreserveinputs(self, psbt):
}
return self.call("unreserveinputs", payload)

def fundpsbt(self, satoshi, feerate, startweight, minconf=None, reserve=True, locktime=None):
def fundpsbt(self, satoshi, feerate, startweight, minconf=None, reserve=True, locktime=None, min_witness_weight=None):
"""
Create a PSBT with inputs sufficient to give an output of satoshi.
"""
Expand All @@ -1255,10 +1262,11 @@ def fundpsbt(self, satoshi, feerate, startweight, minconf=None, reserve=True, lo
"minconf": minconf,
"reserve": reserve,
"locktime": locktime,
"min_witness_weight": min_witness_weight,
}
return self.call("fundpsbt", payload)

def utxopsbt(self, satoshi, feerate, startweight, utxos, reserve=True, reservedok=False, locktime=None):
def utxopsbt(self, satoshi, feerate, startweight, utxos, reserve=True, reservedok=False, locktime=None, min_witness_weight=None):
"""
Create a PSBT with given inputs, to give an output of satoshi.
"""
Expand All @@ -1270,6 +1278,7 @@ def utxopsbt(self, satoshi, feerate, startweight, utxos, reserve=True, reservedo
"reserve": reserve,
"reservedok": reservedok,
"locktime": locktime,
"min_witness_weight": min_witness_weight,
}
return self.call("utxopsbt", payload)

Expand Down
19 changes: 10 additions & 9 deletions lightningd/dual_open_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -306,15 +306,16 @@ hook_extract_amount(struct subd *dualopend,
return true;
}

#define CHECK_CHANGES(set, dir) \
do { \
for (size_t i = 0; i < tal_count(set); i++) { \
ok = psbt_get_serial_id(&set[i].dir.unknowns, &serial_id); \
assert(ok); \
if (serial_id % 2 != opener_side) \
return true; \
} \
} while (false) \
#define CHECK_CHANGES(set, dir) \
do { \
for (size_t i = 0; i < tal_count(set); i++) { \
ok = psbt_get_serial_id(&set[i].dir.unknowns, \
&serial_id); \
assert(ok); \
if (serial_id % 2 != opener_side) \
return true; \
} \
} while (false)

static bool psbt_side_contribs_changed(struct wally_psbt *orig,
struct wally_psbt *new,
Expand Down
9 changes: 8 additions & 1 deletion openingd/dualopend.c
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,14 @@ static char *check_balances(const tal_t *ctx,
initiator_weight);

if (!amount_sat_greater_eq(accepter_diff, accepter_fee)) {
return "accepter fee not covered";
return tal_fmt(ctx, "accepter fee not covered"
" (need %s > have %s)",
type_to_string(ctx,
struct amount_sat,
&accepter_fee),
type_to_string(ctx,
struct amount_sat,
&accepter_diff));
}

if (!amount_sat_greater_eq(initiator_diff, initiator_fee)) {
Expand Down
49 changes: 39 additions & 10 deletions tests/plugins/df_accepter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,15 @@
from pyln.client import Plugin, Millisatoshi
from pyln.proto import bech32_decode
from typing import Iterable, List, Optional
from wallycore import psbt_add_output_at, psbt_from_base64, psbt_to_base64, tx_output_init

from wallycore import (
psbt_add_output_at,
psbt_find_input_unknown,
psbt_from_base64,
psbt_get_input_unknown,
psbt_get_num_inputs,
psbt_to_base64,
tx_output_init,
)

plugin = Plugin()

Expand Down Expand Up @@ -58,6 +65,26 @@ def find_feerate(best, their_min, their_max, our_min, our_max):
return our_max


def find_inputs(b64_psbt):
serial_id_key = bytes.fromhex('fc096c696768746e696e6701')
psbt = psbt_from_base64(b64_psbt)
input_idxs = []

for i in range(psbt_get_num_inputs(psbt)):
idx = psbt_find_input_unknown(psbt, i, serial_id_key)
if idx == 0:
continue
# returned index is off by one, so 0 can be 'not found'
serial_bytes = psbt_get_input_unknown(psbt, i, idx - 1)
serial_id = int.from_bytes(serial_bytes, byteorder='big', signed=False)

# We're the accepter, so our inputs have odd serials
if serial_id % 2:
input_idxs.append(i)

return input_idxs


@plugin.hook('openchannel2')
def on_openchannel(openchannel2, plugin, **kwargs):
# We mirror what the peer does, wrt to funding amount ...
Expand All @@ -79,16 +106,17 @@ def on_openchannel(openchannel2, plugin, **kwargs):
funding = plugin.rpc.fundpsbt(amount,
'{}perkw'.format(feerate),
0, reserve=True,
locktime=locktime)
locktime=locktime,
min_witness_weight=110)
psbt_obj = psbt_from_base64(funding['psbt'])

excess = Millisatoshi(funding['excess_msat'])
change_cost = Millisatoshi(124 * feerate // 1000 * 1000)
change_cost = Millisatoshi(124 * feerate)
dust_limit = Millisatoshi(253 * 1000)
if excess > (dust_limit + change_cost):
addr = plugin.rpc.newaddr()['bech32']
change = excess - change_cost
output = tx_output_init(int(change.to_satoshi()), get_script(addr))
output = tx_output_init(change.to_whole_satoshi(), get_script(addr))
psbt_add_output_at(psbt_obj, 0, 0, output)

return {'result': 'continue', 'psbt': psbt_to_base64(psbt_obj, 0),
Expand All @@ -108,12 +136,13 @@ def on_tx_sign(openchannel2_sign, plugin, **kwargs):
psbt = openchannel2_sign['psbt']

# We only sign the ones with our parity of a serial_id
# FIXME: find the inputs with an odd-serial, these are ours
# the key for a serial_id ::
# our_inputs = [1]
input_idxs = find_inputs(psbt)
if len(input_idxs) > 0:
final_psbt = plugin.rpc.signpsbt(psbt, signonly=input_idxs)['signed_psbt']
else:
final_psbt = psbt

signed_psbt = plugin.rpc.signpsbt(psbt)['signed_psbt']
return {'result': 'continue', 'psbt': signed_psbt}
return {'result': 'continue', 'psbt': final_psbt}


plugin.run()