core-lightning/daemon/wallet.c
Rusty Russell 51de503096 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>
2016-04-12 13:07:03 +09:30

108 lines
2.8 KiB
C

/* 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"
};