forked from ElementsProject/lightning
-
Notifications
You must be signed in to change notification settings - Fork 0
/
wallet.c
105 lines (91 loc) · 2.73 KB
/
wallet.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/* 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_p2wpkh(tx, &w->pubkey);
sig.stype = SIGHASH_ALL;
sign_tx_input(dstate->secpctx, tx, input_num,
redeemscript, tal_count(redeemscript),
p2wpkh_scriptcode(redeemscript, &w->pubkey),
&w->privkey,
&w->pubkey,
&sig.sig);
bitcoin_witness_p2sh_p2wpkh(tx->input,
&tx->input[input_num],
&sig,
&w->pubkey);
tal_free(redeemscript);
}
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_p2wpkh(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"
};