forked from rustyrussell/bitcoin-iterate
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathutxo.c
110 lines (94 loc) · 2.69 KB
/
utxo.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
#include <ccan/err/err.h>
#include "utxo.h"
#include "utils.h"
const u8 *keyof_utxo(const struct utxo *utxo)
{
return utxo->tx;
}
bool utxohash_eq(const struct utxo *utxo, const u8 *key)
{
return memcmp(&utxo->tx, key, sizeof(utxo->tx)) == 0;
}
bool is_unspendable(const struct bitcoin_transaction_output *o)
{
return (o->script_length > 0 && o->script[0] == OP_RETURN);
}
u8 *output_types(struct utxo *utxo)
{
return (u8 *)&utxo->amount[utxo->num_outputs];
}
/* Only classify two-output txs for the moment, assuming round numbers
* are payments. Furthur ideas from Harold:
*
* 1) if the input is P2SH, and there's a P2SH and P2PKH output, then
* it's obvious.
*
* 2) lots of wallets still send change to the same public key hash as
* they were received originally.
*/
static void guess_output_types(const struct bitcoin_transaction *t, u8 *types)
{
if (t->output_count == 2) {
bool first_round = ((t->output[0].amount % 1000) == 0);
bool second_round = ((t->output[1].amount % 1000) == 0);
if (first_round != second_round) {
if (first_round) {
types[0] = PAYMENT_OUTPUT;
types[1] = CHANGE_OUTPUT;
} else {
types[1] = PAYMENT_OUTPUT;
types[0] = CHANGE_OUTPUT;
}
return;
}
}
memset(types, UNKNOWN_OUTPUT, t->output_count);
}
void add_utxo(const tal_t *tal_ctx,
struct utxo_map *utxo_map,
const struct block *b,
const struct bitcoin_transaction *t,
u32 txnum, off_t off)
{
struct utxo *utxo;
unsigned int i;
unsigned int spend_count = 0;
u64 initial_spent = 0;
for (i = 0; i < t->output_count; i++) {
if (!is_unspendable(&t->output[i])) {
spend_count++;
} else {
initial_spent += t->output[i].amount;
}
}
if (spend_count == 0)
return;
utxo = tal_alloc_(tal_ctx, sizeof(*utxo) + (sizeof(utxo->amount[0]) + 1)
* t->output_count, false, TAL_LABEL(struct utxo, ""));
memcpy(utxo->tx, t->sha256, sizeof(utxo->tx));
utxo->num_outputs = t->output_count;
utxo->unspent_outputs = spend_count;
utxo->height = b->height;
utxo->timestamp = b->bh.timestamp;
utxo->unspent = 0;
utxo->spent = initial_spent;
for (i = 0; i < utxo->num_outputs; i++) {
utxo->amount[i] = t->output[i].amount;
utxo->unspent += t->output[i].amount;
}
guess_output_types(t, output_types(utxo));
utxo_map_add(utxo_map, utxo);
}
void release_utxo(struct utxo_map *utxo_map,
const struct bitcoin_transaction_input *i)
{
struct utxo *utxo;
utxo = utxo_map_get(utxo_map, i->hash);
if (!utxo)
errx(1, "Unknown utxo for "SHA_FMT, SHA_VALS(i->hash));
utxo->spent += utxo->amount[i->index];
if (--utxo->unspent_outputs == 0) {
utxo_map_del(utxo_map, utxo);
tal_free(utxo);
}
}