niftynei
4 years ago
committed by
Rusty Russell
2 changed files with 93 additions and 0 deletions
@ -0,0 +1,91 @@ |
|||||
|
#!/usr/bin/env python3 |
||||
|
"""Test plugin for adding inputs/outputs to a dual-funded transaction |
||||
|
""" |
||||
|
|
||||
|
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 |
||||
|
|
||||
|
|
||||
|
plugin = Plugin() |
||||
|
|
||||
|
|
||||
|
def convertbits(data: Iterable[int], frombits: int, tobits: int, pad: bool = True) -> Optional[List[int]]: |
||||
|
"""General power-of-2 base conversion.""" |
||||
|
acc = 0 |
||||
|
bits = 0 |
||||
|
ret = [] |
||||
|
maxv = (1 << tobits) - 1 |
||||
|
max_acc = (1 << (frombits + tobits - 1)) - 1 |
||||
|
for value in data: |
||||
|
if value < 0 or (value >> frombits): |
||||
|
return None |
||||
|
acc = ((acc << frombits) | value) & max_acc |
||||
|
bits += frombits |
||||
|
while bits >= tobits: |
||||
|
bits -= tobits |
||||
|
ret.append((acc >> bits) & maxv) |
||||
|
if pad: |
||||
|
if bits: |
||||
|
ret.append((acc << (tobits - bits)) & maxv) |
||||
|
elif bits >= frombits or ((acc << (tobits - bits)) & maxv): |
||||
|
return None |
||||
|
return ret |
||||
|
|
||||
|
|
||||
|
def get_script(bech_addr): |
||||
|
hrp, data = bech32_decode(bech_addr) |
||||
|
# FIXME: verify hrp matches expected network |
||||
|
wprog = convertbits(data[1:], 5, 8, False) |
||||
|
wit_ver = data[0] |
||||
|
if wit_ver > 16: |
||||
|
raise ValueError("Invalid witness version {}".format(wit_ver[0])) |
||||
|
return bytes([wit_ver + 0x50 if wit_ver > 0 else wit_ver, len(wprog)] + wprog) |
||||
|
|
||||
|
|
||||
|
@plugin.hook('openchannel2') |
||||
|
def on_openchannel(openchannel2, plugin, **kwargs): |
||||
|
# We mirror what the peer does, wrt to funding amount |
||||
|
amount = openchannel2['their_funding'] |
||||
|
feerate = openchannel2['feerate_per_kw_funding'] |
||||
|
locktime = openchannel2['locktime'] |
||||
|
|
||||
|
funding = plugin.rpc.fundpsbt(amount, ''.join([str(feerate), 'perkw']), 0, reserve=True, |
||||
|
locktime=locktime) |
||||
|
psbt_obj = psbt_from_base64(funding['psbt']) |
||||
|
|
||||
|
excess = Millisatoshi(funding['excess_msat']) |
||||
|
change_cost = Millisatoshi(164 * feerate // 1000 * 1000) |
||||
|
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)) |
||||
|
psbt_add_output_at(psbt_obj, 0, 0, output) |
||||
|
|
||||
|
return {'result': 'continue', 'psbt': psbt_to_base64(psbt_obj, 0), |
||||
|
'accepter_funding_msat': amount} |
||||
|
|
||||
|
|
||||
|
@plugin.hook('openchannel2_changed') |
||||
|
def on_tx_changed(openchannel2_changed, plugin, **kwargs): |
||||
|
# In this example, we have nothing to add, so we |
||||
|
# pass back the same psbt that was forwarded in here |
||||
|
return {'result': 'continue', 'psbt': openchannel2_changed['psbt']} |
||||
|
|
||||
|
|
||||
|
@plugin.hook('openchannel2_sign') |
||||
|
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] |
||||
|
|
||||
|
signed_psbt = plugin.rpc.signpsbt(psbt, signonly=our_inputs)['signed_psbt'] |
||||
|
return {'result': 'continue', 'psbt': signed_psbt} |
||||
|
|
||||
|
|
||||
|
plugin.run() |
Loading…
Reference in new issue