From 51de503096b29bcb5ce502440c3b4413a4c7ba0b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 12 Apr 2016 13:07:03 +0930 Subject: [PATCH] daemon: keep track of simple addresses for injecting funds. We need to control the *inputs* to the anchor tx, to make sure they pay to witness scripts (thus the anchor is immalleable). The easiest way to do this is to hand out P2SH addresses for the user, and have them pay into those. Then they hand us that tx and we use it to create the anchor. This is not a long-term solution! Signed-off-by: Rusty Russell --- daemon/Makefile | 2 + daemon/jsonrpc.c | 1 + daemon/jsonrpc.h | 1 + daemon/lightningd.c | 1 + daemon/lightningd.h | 3 ++ daemon/wallet.c | 107 ++++++++++++++++++++++++++++++++++++++++++++ daemon/wallet.h | 18 ++++++++ 7 files changed, 133 insertions(+) create mode 100644 daemon/wallet.c create mode 100644 daemon/wallet.h diff --git a/daemon/Makefile b/daemon/Makefile index 267ba6bee..1e0554823 100644 --- a/daemon/Makefile +++ b/daemon/Makefile @@ -25,6 +25,7 @@ DAEMON_SRC := \ daemon/packets.c \ daemon/secrets.c \ daemon/timeout.c \ + daemon/wallet.c \ daemon/watch.c \ names.c \ state.c @@ -52,6 +53,7 @@ DAEMON_HEADERS := \ daemon/pseudorand.h \ daemon/secrets.h \ daemon/timeout.h \ + daemon/wallet.h \ daemon/watch.h $(DAEMON_OBJS) $(DAEMON_LIB_OBJS) $(DAEMON_CLI_OBJS): $(DAEMON_HEADERS) $(DAEMON_JSMN_HEADERS) $(BITCOIN_HEADERS) $(CORE_HEADERS) $(GEN_HEADERS) $(CCAN_HEADERS) diff --git a/daemon/jsonrpc.c b/daemon/jsonrpc.c index b6184eeaa..b4ff96545 100644 --- a/daemon/jsonrpc.c +++ b/daemon/jsonrpc.c @@ -254,6 +254,7 @@ static const struct json_command *cmdlist[] = { &failhtlc_command, &commit_command, &close_command, + &newaddr_command, /* Developer/debugging options. */ &echo_command, &rhash_command, diff --git a/daemon/jsonrpc.h b/daemon/jsonrpc.h index f65e672e0..84a73d923 100644 --- a/daemon/jsonrpc.h +++ b/daemon/jsonrpc.h @@ -64,4 +64,5 @@ extern const struct json_command failhtlc_command; extern const struct json_command commit_command; extern const struct json_command mocktime_command; extern const struct json_command close_command; +extern const struct json_command newaddr_command; #endif /* LIGHTNING_DAEMON_JSONRPC_H */ diff --git a/daemon/lightningd.c b/daemon/lightningd.c index 679848935..b7629f95b 100644 --- a/daemon/lightningd.c +++ b/daemon/lightningd.c @@ -183,6 +183,7 @@ static struct lightningd_state *lightningd_state(void) | SECP256K1_CONTEXT_SIGN); default_config(&dstate->config); list_head_init(&dstate->bitcoin_req); + list_head_init(&dstate->wallet); dstate->bitcoin_req_running = false; return dstate; } diff --git a/daemon/lightningd.h b/daemon/lightningd.h index b1494ce06..9ea995a9f 100644 --- a/daemon/lightningd.h +++ b/daemon/lightningd.h @@ -81,5 +81,8 @@ struct lightningd_state { /* Outstanding bitcoind requests. */ struct list_head bitcoin_req; bool bitcoin_req_running; + + /* Wallet addresses we maintain. */ + struct list_head wallet; }; #endif /* LIGHTNING_DAEMON_LIGHTNING_H */ diff --git a/daemon/wallet.c b/daemon/wallet.c new file mode 100644 index 000000000..d0420bf52 --- /dev/null +++ b/daemon/wallet.c @@ -0,0 +1,107 @@ +/* Poor man's wallet. + * Needed because bitcoind doesn't (yet) produce segwit outputs, and we need + * such outputs for our anchor tx to make it immalleable. + */ +#include "bitcoin/base58.h" +#include "bitcoin/privkey.h" +#include "bitcoin/script.h" +#include "bitcoin/signature.h" +#include "bitcoin/tx.h" +#include "jsonrpc.h" +#include "lightningd.h" +#include "log.h" +#include "wallet.h" +#include +#include + +struct wallet { + struct list_node list; + struct privkey privkey; + struct pubkey pubkey; + struct ripemd160 p2sh; +}; + +static void new_keypair(struct lightningd_state *dstate, + struct privkey *privkey, struct pubkey *pubkey) +{ + do { + if (RAND_bytes(privkey->secret, sizeof(privkey->secret)) != 1) + fatal("Could not get random bytes for privkey"); + } while (!pubkey_from_privkey(dstate->secpctx, + privkey, pubkey, SECP256K1_EC_COMPRESSED)); +} + +void wallet_add_signed_input(struct lightningd_state *dstate, + const struct wallet *w, + struct bitcoin_tx *tx, + unsigned int input_num) +{ + u8 *redeemscript; + struct bitcoin_signature sig; + assert(input_num < tx->input_count); + + redeemscript = bitcoin_redeem_single(tx, &w->pubkey); + + sig.stype = SIGHASH_ALL; + sign_tx_input(dstate->secpctx, tx, input_num, + redeemscript, tal_count(redeemscript), + NULL, + &w->privkey, + &w->pubkey, + &sig.sig); + + tx->input[input_num].script + = scriptsig_p2sh_single_sig(tx->input, + redeemscript, + tal_count(redeemscript), + &sig); + tx->input[input_num].script_length + = tal_count(tx->input[input_num].script); +} + +struct wallet *wallet_can_spend(struct lightningd_state *dstate, + const struct bitcoin_tx_output *output) +{ + struct ripemd160 h; + struct wallet *w; + + if (!is_p2sh(output->script, output->script_length)) + return NULL; + + memcpy(&h, output->script + 2, 20); + list_for_each(&dstate->wallet, w, list) { + if (structeq(&h, &w->p2sh)) + return w; + } + return NULL; +} + +static void json_newaddr(struct command *cmd, + const char *buffer, const jsmntok_t *params) +{ + struct json_result *response = new_json_result(cmd); + struct wallet *w = tal(cmd->dstate, struct wallet); + u8 *redeemscript; + struct sha256 h; + + new_keypair(cmd->dstate, &w->privkey, &w->pubkey); + redeemscript = bitcoin_redeem_single(cmd, &w->pubkey); + sha256(&h, redeemscript, tal_count(redeemscript)); + ripemd160(&w->p2sh, h.u.u8, sizeof(h)); + + list_add_tail(&cmd->dstate->wallet, &w->list); + + json_object_start(response, NULL); + json_add_string(response, "address", + p2sh_to_base58(cmd, cmd->dstate->config.testnet, + &w->p2sh)); + json_object_end(response); + command_success(cmd, response); +} + +const struct json_command newaddr_command = { + "newaddr", + json_newaddr, + "Get a new address to fund a channel", + "Returns {address} a p2sh address" +}; diff --git a/daemon/wallet.h b/daemon/wallet.h new file mode 100644 index 000000000..ffa8509f7 --- /dev/null +++ b/daemon/wallet.h @@ -0,0 +1,18 @@ +#ifndef LIGHTNING_DAEMON_WALLET_H +#define LIGHTNING_DAEMON_WALLET_H +#include "config.h" + +struct wallet; +struct lightningd_state; +struct bitcoin_tx; +struct bitcoin_tx_output; + +void wallet_add_signed_input(struct lightningd_state *dstate, + const struct wallet *w, + struct bitcoin_tx *tx, + unsigned int input_num); + +struct wallet *wallet_can_spend(struct lightningd_state *dstate, + const struct bitcoin_tx_output *output); + +#endif /* LIGHTNING_DAEMON_WALLET_H */