Skip to content

Commit cca926d

Browse files
committed
added wallet paths to change outputs in funding tx. (#27)
* added wallet paths to change outputs in funding tx. fixed txid formatting (reversed) in debugging output. added missing redeemscripts to tx submitted to handle_sign_withdrawal marked some tests as skip when remote_hsmd because of policies marked many tests as flaky * turned off SLOW_MACHINE in run-all-tests * removed the extra flaky designations
1 parent ec6b161 commit cca926d

14 files changed

+140
-20
lines changed

contrib/remote_hsmd/dump.cc

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ string dump_hex(const void *vptr, size_t sz)
4444

4545
string dump_bitcoin_txid(const struct bitcoin_txid *txid)
4646
{
47-
return dump_hex(txid->shad.sha.u.u8, sizeof(txid->shad.sha.u.u8));
47+
// reverse the bytes, a-la bitcoind
48+
struct sha256_double rev = txid->shad;
49+
reverse_bytes(rev.sha.u.u8, sizeof(rev.sha.u.u8));
50+
return dump_hex(rev.sha.u.u8, sizeof(rev.sha.u.u8));
4851
}
4952

5053
string dump_bitcoin_signature(const struct bitcoin_signature *sp)
@@ -213,6 +216,7 @@ string dump_wally_tx_witness_stack(const struct wally_tx_witness_stack *sp)
213216
string dump_wally_keypath_item(const struct wally_map_item *ip)
214217
{
215218
size_t npath = (ip->value_len - BIP32_KEY_FINGERPRINT_LEN) / sizeof(uint32_t);
219+
uint32_t * path = (uint32_t *) (ip->value + BIP32_KEY_FINGERPRINT_LEN);
216220
ostringstream ostrm;
217221
ostrm << "{ ";
218222
ostrm << "\"pubkey\":" << dump_hex(ip->key, ip->key_len);
@@ -223,9 +227,7 @@ string dump_wally_keypath_item(const struct wally_map_item *ip)
223227
for (size_t ii = 0; ii < npath; ++ii) {
224228
if (ii != 0)
225229
ostrm << ",";
226-
uint32_t pelem = *(uint32_t *)
227-
ip->value + BIP32_KEY_FINGERPRINT_LEN + ii * sizeof(uint32_t);
228-
ostrm << pelem;
230+
ostrm << le32_to_cpu(path[ii]);
229231
}
230232
ostrm << " ]";
231233
ostrm << " }";
@@ -481,3 +483,15 @@ string dump_rhashes(const struct sha256 *rhashes, size_t num_rhashes)
481483
ostrm << "]";
482484
return ostrm.str();
483485
}
486+
487+
/* <sigh>. Bitcoind represents hashes as little-endian for RPC. */
488+
void reverse_bytes(u8 *arr, size_t len)
489+
{
490+
unsigned int i;
491+
492+
for (i = 0; i < len / 2; i++) {
493+
unsigned char tmp = arr[i];
494+
arr[i] = arr[len - 1 - i];
495+
arr[len - 1 - i] = tmp;
496+
}
497+
}

contrib/remote_hsmd/dump.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,7 @@ std::string dump_wally_psbt(const struct wally_psbt *psbt);
3838
std::string dump_tx(const struct bitcoin_tx *tx);
3939
std::string dump_rhashes(const struct sha256 *rhashes, size_t num_rhashes);
4040

41+
// needed for formatting txid
42+
void reverse_bytes(u8 *arr, size_t len);
43+
4144
#endif /* LIGHTNING_CONTRIB_REMOTE_HSMD_DUMP_H */

contrib/remote_hsmd/hsmd.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,11 +1288,11 @@ static struct io_plan *handle_ready_channel(struct io_conn *conn,
12881288
&push_value,
12891289
&funding_txid,
12901290
funding_txout,
1291-
local_to_self_delay,
1291+
local_to_self_delay, // locally imposed on counterparty to_self outputs
12921292
local_shutdown_script,
12931293
&remote_basepoints,
12941294
&remote_funding_pubkey,
1295-
remote_to_self_delay,
1295+
remote_to_self_delay, // counterparty imposed on our to_self outputs
12961296
remote_shutdown_script,
12971297
option_static_remotekey,
12981298
option_anchor_outputs);
@@ -1334,7 +1334,7 @@ static struct io_plan *handle_sign_withdrawal_tx(struct io_conn *conn,
13341334

13351335
u8 *** wits;
13361336
proxy_stat rv = proxy_handle_sign_withdrawal_tx(
1337-
&c->id, c->dbid, outputs, utxos, psbt, &wits);
1337+
outputs, utxos, psbt, &wits);
13381338
if (PROXY_PERMANENT(rv))
13391339
status_failed(STATUS_FAIL_INTERNAL_ERROR,
13401340
"proxy_%s failed: %s", __FUNCTION__,

contrib/remote_hsmd/proxy.cc

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ extern "C" {
99
#include <bitcoin/chainparams.h>
1010
#include <bitcoin/privkey.h>
1111
#include <bitcoin/psbt.h>
12+
#include <bitcoin/script.h>
1213
#include <bitcoin/short_channel_id.h>
1314
#include <bitcoin/tx.h>
1415
#include <common/derive_basepoints.h>
@@ -588,12 +589,12 @@ proxy_stat proxy_handle_ready_channel(
588589
req.set_push_value_msat(push_value->millisatoshis);
589590
marshal_outpoint(funding_txid,
590591
funding_txout, req.mutable_funding_outpoint());
591-
req.set_holder_to_self_delay(holder_to_self_delay);
592+
req.set_holder_selected_contest_delay(holder_to_self_delay);
592593
marshal_script(holder_shutdown_script,
593594
req.mutable_holder_shutdown_script());
594595
marshal_basepoints(counterparty_basepoints, counterparty_funding_pubkey,
595596
req.mutable_counterparty_basepoints());
596-
req.set_counterparty_to_self_delay(counterparty_to_self_delay);
597+
req.set_counterparty_selected_contest_delay(counterparty_to_self_delay);
597598
marshal_script(counterparty_shutdown_script,
598599
req.mutable_counterparty_shutdown_script());
599600
if (option_anchor_outputs)
@@ -623,33 +624,58 @@ proxy_stat proxy_handle_ready_channel(
623624
}
624625

625626
proxy_stat proxy_handle_sign_withdrawal_tx(
626-
struct node_id *peer_id,
627-
u64 dbid,
628627
struct bitcoin_tx_output **outputs,
629628
struct utxo **utxos,
630629
struct wally_psbt *psbt,
631630
u8 ****o_wits)
632631
{
633632
STATUS_DEBUG(
634633
"%s:%d %s { "
635-
"\"self_id\":%s, \"peer_id\":%s, \"dbid\":%" PRIu64 ", "
634+
"\"self_id\":%s, "
636635
"\"utxos\":%s, \"outputs\":%s, \"psbt\":%s }",
637636
__FILE__, __LINE__, __FUNCTION__,
638637
dump_node_id(&self_id).c_str(),
639-
dump_node_id(peer_id).c_str(),
640-
dbid,
641638
dump_utxos((const struct utxo **)utxos).c_str(),
642639
dump_bitcoin_tx_outputs(
643640
(const struct bitcoin_tx_output **)outputs).c_str(),
644641
dump_wally_psbt(psbt).c_str()
645642
);
646643

647644
last_message = "";
645+
646+
// This code is mimicking psbt_txid at bitcoin/psbt.c:796:
647+
//
648+
/* You can *almost* take txid of global tx. But @niftynei thought
649+
* about this far more than me and pointed out that P2SH
650+
* inputs would not be represented, so here we go. */
651+
struct wally_tx *tx;
652+
tal_wally_start();
653+
wally_tx_clone_alloc(psbt->tx, 0, &tx);
654+
for (size_t i = 0; i < tx->num_inputs; i++) {
655+
if (psbt->inputs[i].final_scriptsig) {
656+
wally_tx_set_input_script(tx, i,
657+
psbt->inputs[i].final_scriptsig,
658+
psbt->inputs[i].final_scriptsig_len);
659+
} else if (psbt->inputs[i].redeem_script) {
660+
u8 *script;
661+
662+
/* P2SH requires push of the redeemscript, from libwally src */
663+
script = tal_arr(tmpctx, u8, 0);
664+
script_push_bytes(&script,
665+
psbt->inputs[i].redeem_script,
666+
psbt->inputs[i].redeem_script_len);
667+
wally_tx_set_input_script(tx, i, script, tal_bytelen(script));
668+
}
669+
}
670+
tal_wally_end(tal_steal(psbt, tx));
671+
672+
648673
SignFundingTxRequest req;
649674
marshal_node_id(&self_id, req.mutable_node_id());
650-
marshal_channel_nonce(peer_id, dbid, req.mutable_channel_nonce());
651675

652-
req.mutable_tx()->set_raw_tx_bytes(serialized_wtx(psbt->tx, true));
676+
// Serialize the tx we modified above which includes witscripts.
677+
req.mutable_tx()->set_raw_tx_bytes(serialized_wtx(tx, true));
678+
653679
assert(psbt->tx->num_inputs >= tal_count(utxos));
654680
size_t uu = 0;
655681
for (size_t ii = 0; ii < psbt->tx->num_inputs; ++ii) {
@@ -664,6 +690,20 @@ proxy_stat proxy_handle_sign_withdrawal_tx(
664690
}
665691
assert(uu == tal_count(utxos));
666692

693+
for (size_t ii = 0; ii < psbt->tx->num_outputs; ++ii) {
694+
OutputDescriptor *odesc = req.mutable_tx()->add_output_descs();
695+
struct wally_map *mp = &psbt->outputs[ii].keypaths;
696+
if (mp->num_items == 1) {
697+
const struct wally_map_item *ip = &mp->items[0];
698+
size_t npath =
699+
(ip->value_len - BIP32_KEY_FINGERPRINT_LEN) / sizeof(uint32_t);
700+
uint32_t *path = (uint32_t *) (ip->value + BIP32_KEY_FINGERPRINT_LEN);
701+
for (size_t jj = 0; jj < npath; ++jj) {
702+
odesc->mutable_key_loc()->add_key_path(le32_to_cpu(path[jj]));
703+
}
704+
}
705+
}
706+
667707
ClientContext context;
668708
SignFundingTxReply rsp;
669709
Status status = stub->SignFundingTx(&context, req, &rsp);

contrib/remote_hsmd/proxy.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ proxy_stat proxy_handle_ready_channel(
7979
bool option_anchor_outputs);
8080

8181
proxy_stat proxy_handle_sign_withdrawal_tx(
82-
struct node_id *peer_id, u64 dbid,
8382
struct bitcoin_tx_output **outputs,
8483
struct utxo **utxos,
8584
struct wally_psbt *psbt,
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
#!/usr/bin/sh
22

3-
4-
53
SUBDAEMON='hsmd:remote_hsmd' \
64
REMOTE_SIGNER_CMD=$(pwd)/../rust-lightning-signer/target/debug/server \
75
make \
86
-j32 PYTEST_PAR=64 \
97
DEVELOPER=1 \
108
VALGRIND=0 \
11-
SLOW_MACHINE=1 \
9+
SLOW_MACHINE=0 \
1210
PYTEST_MOREOPTS='--timeout=300 --timeout_method=thread' \
1311
pytest
1412

tests/test_closing.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2435,6 +2435,7 @@ def test_permfail_htlc_out(node_factory, bitcoind, executor):
24352435

24362436

24372437
@pytest.mark.developer("needs DEVELOPER=1")
2438+
@unittest.skipIf(os.getenv('SUBDAEMON') == 'hsmd:remote_hsmd', "policy: can't withdraw to non-wallet address")
24382439
def test_permfail(node_factory, bitcoind):
24392440
l1, l2 = node_factory.line_graph(2)
24402441

tests/test_connection.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2628,6 +2628,7 @@ def mock_sendrawtransaction(r):
26282628

26292629

26302630
@pytest.mark.developer("needs dev_fail")
2631+
@unittest.skipIf(os.getenv('SUBDAEMON') == 'hsmd:remote_hsmd', "policy: can't withdraw to non-wallet address")
26312632
def test_no_fee_estimate(node_factory, bitcoind, executor):
26322633
l1 = node_factory.get_node(start=False, options={'dev-no-fake-fees': True})
26332634

tests/test_misc.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ def is_p2wpkh(output):
492492
assert only_one(fundingtx['vin'])['txid'] == res['wallettxid']
493493

494494

495+
@unittest.skipIf(os.getenv('SUBDAEMON') == 'hsmd:remote_hsmd', "policy: can't withdraw to non-wallet address")
495496
def test_withdraw_misc(node_factory, bitcoind, chainparams):
496497
def dont_spend_outputs(n, txid):
497498
"""Reserve both outputs (we assume there are two!) in case any our ours, so we don't spend change: wrecks accounting checks"""

tests/test_plugin.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2090,6 +2090,7 @@ def test_3847_repro(node_factory, bitcoind):
20902090
l1.rpc.paystatus(i1)
20912091

20922092

2093+
@unittest.skipIf(os.getenv('SUBDAEMON') == 'hsmd:remote_hsmd', "trouble managing remotesigner when node killed this way")
20932094
def test_important_plugin(node_factory):
20942095
# Cache it here.
20952096
pluginsdir = os.path.join(os.path.dirname(__file__), "plugins")

tests/test_wallet.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020

2121
@unittest.skipIf(TEST_NETWORK != 'regtest', "Test relies on a number of example addresses valid only in regtest")
22+
@unittest.skipIf(os.getenv('SUBDAEMON') == 'hsmd:remote_hsmd', "policy: can't withdraw to non-wallet address")
2223
def test_withdraw(node_factory, bitcoind):
2324
amount = 1000000
2425
# Don't get any funds from previous runs.
@@ -672,6 +673,7 @@ def test_utxopsbt(node_factory, bitcoind, chainparams):
672673
reservedok=True)
673674

674675

676+
@unittest.skipIf(os.getenv('SUBDAEMON') == 'hsmd:remote_hsmd', "policy: can't withdraw to non-wallet address")
675677
def test_sign_and_send_psbt(node_factory, bitcoind, chainparams):
676678
"""
677679
Tests for the sign + send psbt RPCs
@@ -874,6 +876,7 @@ def test_sign_and_send_psbt(node_factory, bitcoind, chainparams):
874876
check_coin_moves(l1, 'wallet', wallet_coin_mvts, chainparams)
875877

876878

879+
@unittest.skipIf(os.getenv('SUBDAEMON') == 'hsmd:remote_hsmd', "policy: can't withdraw to non-wallet address")
877880
def test_txsend(node_factory, bitcoind, chainparams):
878881
amount = 1000000
879882
l1 = node_factory.get_node(random_hsm=True)
@@ -1291,6 +1294,7 @@ def test_withdraw_nlocktime_fuzz(node_factory, bitcoind):
12911294
raise Exception("No transaction with fuzzed nLockTime !")
12921295

12931296

1297+
@unittest.skipIf(os.getenv('SUBDAEMON') == 'hsmd:remote_hsmd', "policy: can't withdraw to non-wallet address")
12941298
def test_multiwithdraw_simple(node_factory, bitcoind):
12951299
"""
12961300
Test simple multiwithdraw usage.

wallet/wallet.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,30 @@ bool wallet_can_spend(struct wallet *w, const u8 *script,
681681
return false;
682682
}
683683

684+
void wallet_set_keypath(struct wallet *w, u32 index, struct wally_map *map_in)
685+
{
686+
log_debug(w->log, "wallet_set_keypath index=%d", index);
687+
688+
struct ext_key ext;
689+
if (bip32_key_from_parent(w->bip32_base, index, BIP32_FLAG_KEY_PUBLIC, &ext) != WALLY_OK) {
690+
abort();
691+
}
692+
693+
u8 fingerprint[BIP32_KEY_FINGERPRINT_LEN];
694+
if (bip32_key_get_fingerprint(&ext, fingerprint, sizeof(fingerprint)) != WALLY_OK) {
695+
abort();
696+
}
697+
698+
u32 path[1];
699+
path[0] = index;
700+
if (wally_map_add_keypath_item(map_in,
701+
ext.pub_key, sizeof(ext.pub_key),
702+
fingerprint, sizeof(fingerprint),
703+
path, 1) != WALLY_OK) {
704+
abort();
705+
}
706+
}
707+
684708
s64 wallet_get_newindex(struct lightningd *ld)
685709
{
686710
u64 newidx = db_get_intvar(ld->wallet->db, "bip32_max_index", 0) + 1;

wallet/wallet.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,11 @@ void wallet_confirm_utxos(struct wallet *w, const struct utxo **utxos);
463463
bool wallet_can_spend(struct wallet *w, const u8 *script,
464464
u32 *index, bool *output_is_p2sh);
465465

466+
/**
467+
* wallet_set_keypath - set the keypath to the given wallet entry.
468+
*/
469+
void wallet_set_keypath(struct wallet *w, u32 index, struct wally_map *map_in);
470+
466471
/**
467472
* wallet_get_newindex - get a new index from the wallet.
468473
* @ld: (in) lightning daemon

wallet/walletrpc.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,30 @@ static struct command_result *match_psbt_inputs_to_utxos(struct command *cmd,
660660
return NULL;
661661
}
662662

663+
static struct command_result *match_psbt_outputs_to_wallet(struct wally_psbt *psbt,
664+
struct wallet *w)
665+
{
666+
assert(psbt->tx->num_outputs == psbt->num_outputs);
667+
tal_wally_start();
668+
for (size_t outndx = 0; outndx < psbt->num_outputs; ++outndx) {
669+
u32 index;
670+
bool is_p2sh;
671+
const u8 *script;
672+
673+
script = wally_tx_output_get_script(tmpctx,
674+
&psbt->tx->outputs[outndx]);
675+
if (!script)
676+
continue;
677+
678+
if (!wallet_can_spend(w, script, &index, &is_p2sh))
679+
continue;
680+
681+
wallet_set_keypath(w, index, &psbt->outputs[outndx].keypaths);
682+
}
683+
tal_wally_end(psbt);
684+
return NULL;
685+
}
686+
663687
static struct command_result *param_input_numbers(struct command *cmd,
664688
const char *name,
665689
const char *buffer,
@@ -723,6 +747,11 @@ static struct command_result *json_signpsbt(struct command *cmd,
723747
return command_fail(cmd, LIGHTNINGD,
724748
"No wallet inputs to sign");
725749

750+
// Update the keypaths on any outputs that are in our wallet (change addresses).
751+
res = match_psbt_outputs_to_wallet(psbt, cmd->ld->wallet);
752+
if (res)
753+
return res;
754+
726755
/* FIXME: hsm will sign almost anything, but it should really
727756
* fail cleanly (not abort!) and let us report the error here. */
728757
u8 *msg = towire_hsmd_sign_withdrawal(cmd,

0 commit comments

Comments
 (0)