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 <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2016-04-12 13:07:03 +09:30
parent 6b956ea22a
commit 51de503096
7 changed files with 133 additions and 0 deletions

View File

@ -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)

View File

@ -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,

View File

@ -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 */

View File

@ -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;
}

View File

@ -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 */

107
daemon/wallet.c Normal file
View File

@ -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 <ccan/structeq/structeq.h>
#include <openssl/rand.h>
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"
};

18
daemon/wallet.h Normal file
View File

@ -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 */