forked from ElementsProject/lightning
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathwallet.c
144 lines (123 loc) · 3.57 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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/* 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 "db.h"
#include "jsonrpc.h"
#include "lightningd.h"
#include "log.h"
#include "wallet.h"
#include <ccan/structeq/structeq.h>
#include <sodium/randombytes.h>
struct wallet {
struct list_node list;
struct privkey privkey;
struct pubkey pubkey;
struct ripemd160 p2sh;
};
bool restore_wallet_address(struct lightningd_state *dstate,
const struct privkey *privkey)
{
struct wallet *w = tal(dstate, struct wallet);
u8 *redeemscript;
struct sha256 h;
w->privkey = *privkey;
if (!pubkey_from_privkey(&w->privkey, &w->pubkey))
return false;
redeemscript = bitcoin_redeem_p2wpkh(w, &w->pubkey);
sha256(&h, redeemscript, tal_count(redeemscript));
ripemd160(&w->p2sh, h.u.u8, sizeof(h));
list_add_tail(&dstate->wallet, &w->list);
tal_free(redeemscript);
return true;
}
static void new_keypair(struct privkey *privkey, struct pubkey *pubkey)
{
do {
randombytes_buf(privkey->secret, sizeof(privkey->secret));
} while (!pubkey_from_privkey(privkey, pubkey));
}
static struct wallet *find_by_pubkey(struct lightningd_state *dstate,
const struct pubkey *walletkey)
{
struct wallet *w;
list_for_each(&dstate->wallet, w, list) {
if (pubkey_eq(walletkey, &w->pubkey))
return w;
}
return NULL;
}
bool wallet_add_signed_input(struct lightningd_state *dstate,
const struct pubkey *walletkey,
struct bitcoin_tx *tx,
unsigned int input_num)
{
u8 *redeemscript;
struct bitcoin_signature sig;
struct wallet *w = find_by_pubkey(dstate, walletkey);
assert(input_num < tx->input_count);
if (!w)
return false;
redeemscript = bitcoin_redeem_p2wpkh(tx, &w->pubkey);
sig.stype = SIGHASH_ALL;
sign_tx_input(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);
return true;
}
bool wallet_can_spend(struct lightningd_state *dstate,
const struct bitcoin_tx_output *output,
struct pubkey *walletkey)
{
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)) {
*walletkey = w->pubkey;
return true;
}
}
return false;
}
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(&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);
db_add_wallet_privkey(cmd->dstate, &w->privkey);
json_object_start(response, NULL);
json_add_string(response, "address",
p2sh_to_base58(cmd, cmd->dstate->testnet, &w->p2sh));
json_object_end(response);
command_success(cmd, response);
}
static const struct json_command newaddr_command = {
"newaddr",
json_newaddr,
"Get a new address to fund a channel",
"Returns {address} a p2sh address"
};
AUTODATA(json_command, &newaddr_command);