line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Bitcoin::Crypto::Transaction::UTXO; |
2
|
|
|
|
|
|
|
$Bitcoin::Crypto::Transaction::UTXO::VERSION = '2.000_01'; # TRIAL |
3
|
|
|
|
|
|
|
$Bitcoin::Crypto::Transaction::UTXO::VERSION = '2.00001'; |
4
|
9
|
|
|
9
|
|
136
|
use v5.10; |
|
9
|
|
|
|
|
41
|
|
5
|
9
|
|
|
9
|
|
88
|
use strict; |
|
9
|
|
|
|
|
30
|
|
|
9
|
|
|
|
|
218
|
|
6
|
9
|
|
|
9
|
|
63
|
use warnings; |
|
9
|
|
|
|
|
28
|
|
|
9
|
|
|
|
|
250
|
|
7
|
|
|
|
|
|
|
|
8
|
9
|
|
|
9
|
|
79
|
use Moo; |
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
75
|
|
9
|
9
|
|
|
9
|
|
4519
|
use Mooish::AttributeBuilder -standard; |
|
9
|
|
|
|
|
30
|
|
|
9
|
|
|
|
|
103
|
|
10
|
9
|
|
|
9
|
|
1296
|
use Type::Params -sigs; |
|
9
|
|
|
|
|
46
|
|
|
9
|
|
|
|
|
99
|
|
11
|
|
|
|
|
|
|
|
12
|
9
|
|
|
9
|
|
9222
|
use Bitcoin::Crypto::Transaction; |
|
9
|
|
|
|
|
50
|
|
|
9
|
|
|
|
|
390
|
|
13
|
9
|
|
|
9
|
|
70
|
use Bitcoin::Crypto::Transaction::Output; |
|
9
|
|
|
|
|
26
|
|
|
9
|
|
|
|
|
313
|
|
14
|
9
|
|
|
9
|
|
58
|
use Bitcoin::Crypto::Types qw(IntMaxBits Int PositiveOrZeroInt ByteStr InstanceOf HashRef Str Object Maybe CodeRef); |
|
9
|
|
|
|
|
41
|
|
|
9
|
|
|
|
|
95
|
|
15
|
9
|
|
|
9
|
|
37580
|
use Bitcoin::Crypto::Util qw(to_format); |
|
9
|
|
|
|
|
44
|
|
|
9
|
|
|
|
|
436
|
|
16
|
9
|
|
|
9
|
|
79
|
use Bitcoin::Crypto::Exception; |
|
9
|
|
|
|
|
39
|
|
|
9
|
|
|
|
|
6253
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
my %utxos; |
19
|
|
|
|
|
|
|
my $loader; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
has param 'txid' => ( |
22
|
|
|
|
|
|
|
coerce => ByteStr->create_child_type( |
23
|
|
|
|
|
|
|
constraint => q{ length $_ == 32 }, |
24
|
|
|
|
|
|
|
coercion => 1 |
25
|
|
|
|
|
|
|
), |
26
|
|
|
|
|
|
|
); |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# NOTE: ideally, utxo should point to a transaction, and transaction should |
29
|
|
|
|
|
|
|
# point to a block |
30
|
|
|
|
|
|
|
has option 'block' => ( |
31
|
|
|
|
|
|
|
isa => InstanceOf ['Bitcoin::Crypto::Block'], |
32
|
|
|
|
|
|
|
); |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
has param 'output_index' => ( |
35
|
|
|
|
|
|
|
isa => IntMaxBits [32], |
36
|
|
|
|
|
|
|
); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
has param 'output' => ( |
39
|
|
|
|
|
|
|
coerce => (InstanceOf ['Bitcoin::Crypto::Transaction::Output']) |
40
|
|
|
|
|
|
|
->plus_coercions(HashRef q{ Bitcoin::Crypto::Transaction::Output->new($_) }), |
41
|
|
|
|
|
|
|
); |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
signature_for register => ( |
44
|
|
|
|
|
|
|
method => Object, |
45
|
|
|
|
|
|
|
positional => [], |
46
|
|
|
|
|
|
|
); |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
sub register |
49
|
|
|
|
|
|
|
{ |
50
|
|
|
|
|
|
|
my ($self) = @_; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
# Do not store NULLDATA UTXOs |
53
|
|
|
|
|
|
|
return $self |
54
|
|
|
|
|
|
|
if $self->output->is_standard && $self->output->locking_script->type eq 'NULLDATA'; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
$utxos{$self->txid}[$self->output_index] = $self; |
57
|
|
|
|
|
|
|
return $self; |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
signature_for unregister => ( |
61
|
|
|
|
|
|
|
method => Object, |
62
|
|
|
|
|
|
|
positional => [], |
63
|
|
|
|
|
|
|
); |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
sub unregister |
66
|
|
|
|
|
|
|
{ |
67
|
|
|
|
|
|
|
my ($self) = @_; |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
delete $utxos{$self->txid}[$self->output_index]; |
70
|
|
|
|
|
|
|
return $self; |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
signature_for get => ( |
74
|
|
|
|
|
|
|
method => Str, |
75
|
|
|
|
|
|
|
positional => [ByteStr, PositiveOrZeroInt], |
76
|
|
|
|
|
|
|
); |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub get |
79
|
|
|
|
|
|
|
{ |
80
|
|
|
|
|
|
|
my ($class, $txid, $outid) = @_; |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
my $utxo = $utxos{$txid}[$outid]; |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# NOTE: loader should unregister the utxo in its own store |
85
|
|
|
|
|
|
|
if (!$utxo && defined $loader) { |
86
|
|
|
|
|
|
|
$utxo = $loader->($txid, $outid); |
87
|
|
|
|
|
|
|
$utxo->register if $utxo; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
Bitcoin::Crypto::Exception::UTXO->raise( |
91
|
|
|
|
|
|
|
"no UTXO registered for transaction id @{[to_format [hex => $txid]]} and output index $outid" |
92
|
|
|
|
|
|
|
) unless $utxo; |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
return $utxo; |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
signature_for set_loader => ( |
98
|
|
|
|
|
|
|
method => Str, |
99
|
|
|
|
|
|
|
positional => [Maybe[CodeRef]], |
100
|
|
|
|
|
|
|
); |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub set_loader |
103
|
|
|
|
|
|
|
{ |
104
|
|
|
|
|
|
|
my ($class, $new_loader) = @_; |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
$loader = $new_loader; |
107
|
|
|
|
|
|
|
return; |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
signature_for extract => ( |
111
|
|
|
|
|
|
|
method => Str, |
112
|
|
|
|
|
|
|
positional => [ByteStr], |
113
|
|
|
|
|
|
|
); |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
sub extract |
116
|
|
|
|
|
|
|
{ |
117
|
|
|
|
|
|
|
my ($class, $serialized_tx) = @_; |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
# hijack the utxo loader |
120
|
|
|
|
|
|
|
my $old_loader = $loader; |
121
|
|
|
|
|
|
|
$loader = sub { |
122
|
|
|
|
|
|
|
if ($old_loader) { |
123
|
|
|
|
|
|
|
my $loaded = $old_loader->(@_); |
124
|
|
|
|
|
|
|
return $loaded if $loaded; |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
return $class->new( |
128
|
|
|
|
|
|
|
txid => shift, |
129
|
|
|
|
|
|
|
output_index => shift, |
130
|
|
|
|
|
|
|
output => { |
131
|
|
|
|
|
|
|
locking_script => [NULLDATA => 'stub utxo'], |
132
|
|
|
|
|
|
|
value => 0, |
133
|
|
|
|
|
|
|
}, |
134
|
|
|
|
|
|
|
); |
135
|
|
|
|
|
|
|
}; |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
my $tx = Bitcoin::Crypto::Transaction->from_serialized($serialized_tx); |
138
|
|
|
|
|
|
|
$loader = $old_loader; |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
$tx->update_utxos; |
141
|
|
|
|
|
|
|
return; |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
1; |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
__END__ |
147
|
|
|
|
|
|
|
=head1 NAME |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
Bitcoin::Crypto::Transaction::UTXO - Unspent transaction output instance |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=head1 SYNOPSIS |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
use Bitcoin::Crypto qw(btc_utxo); |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# register the utxos automatically from the serialized transaction |
156
|
|
|
|
|
|
|
btc_utxo->extract($serialized_tx); |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# create the utxo manually |
159
|
|
|
|
|
|
|
my $utxo = btc_utxo->new( |
160
|
|
|
|
|
|
|
txid => [hex => '94e519b9c0f43228e3dc841d838fc7372de95345206ef936ac6020889abe0457'], |
161
|
|
|
|
|
|
|
output_index => 1, |
162
|
|
|
|
|
|
|
output => { |
163
|
|
|
|
|
|
|
locking_script => [P2PKH => '1HrfeGdVP4d1uAdbSknzeaFpDFQVJyVpLu'], |
164
|
|
|
|
|
|
|
value => 1_02119131, |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
); |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# register |
169
|
|
|
|
|
|
|
$utxo->register; |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
# find the utxo |
172
|
|
|
|
|
|
|
btc_utxo->get([hex => '94e519b9c0f43228e3dc841d838fc7372de95345206ef936ac6020889abe0457'], 1); |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# unregister |
175
|
|
|
|
|
|
|
$utxo->unregister; |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=head1 DESCRIPTION |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
UTXO is a transaction output which hasn't been spent yet. All transaction |
180
|
|
|
|
|
|
|
inputs must be UTXOs. Bitcoin::Crypto requires you to register UTXOs before you |
181
|
|
|
|
|
|
|
can create a transaction. |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=head1 INTERFACE |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
=head2 Attributes |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
=head3 txid |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
A bytestring - id of the source transaction. |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
I<Available in the constructor>. |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=head3 output_index |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
A positive or zero integer which is the index of the output in the source |
196
|
|
|
|
|
|
|
transaction. |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
I<Available in the constructor>. |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=head3 block |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
Optional instance of L<Bitcoin::Crypto::Block>. |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
I<Available in the constructor>. |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=head3 output |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
Instance of L<Bitcoin::Crypto::Transaction::Output>. A hash reference will be |
209
|
|
|
|
|
|
|
coerced into an object by passing it to the constructor. |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
I<Available in the constructor>. |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=head2 Methods |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=head3 new |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
$tx = $class->new(%args) |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
This is a standard Moo constructor, which can be used to create the object. It |
220
|
|
|
|
|
|
|
takes arguments specified in L</Attributes>. |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
Returns class instance. |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=head3 register |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
$object = $object->register() |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
Registers the given UTXO. It will be held in memory and will be available to |
229
|
|
|
|
|
|
|
fetch using L</get>. |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
=head3 unregister |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
$object = $object->unregister() |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
Does the opposite of L</register>. |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=head3 get |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
$utxo = $object->get($txid, $output_index); |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
Returns the UTXO registered with given txid and output index. Throws an |
242
|
|
|
|
|
|
|
exception if it cannot be found or loaded. |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=head3 set_loader |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
$class->set_loader(sub { ... }) |
247
|
|
|
|
|
|
|
$class->set_loader(undef) |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
Replaces an UTXO loader. |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
The subroutine should accept the same parameters as L</get> and return a |
252
|
|
|
|
|
|
|
constructed UTXO object. If possible, the loader should not return the same |
253
|
|
|
|
|
|
|
UTXO twice in a single runtime of the script. |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
Returns nothing. Passing undef disables the loader. |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
=head3 extract |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
$class->extract($serialized_tx) |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
Extracts all outputs from the C<$serialized_tx> (a bytestring). |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
Returns nothing. |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
=head1 EXCEPTIONS |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
This module throws an instance of L<Bitcoin::Crypto::Exception> if it |
268
|
|
|
|
|
|
|
encounters an error. It can produce the following error types from the |
269
|
|
|
|
|
|
|
L<Bitcoin::Crypto::Exception> namespace: |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
=over |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=item * Bitcoin::Crypto::Exception::UTXO - UTXO was not found |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
=back |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=head1 SEE ALSO |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
=over |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=item L<Bitcoin::Crypto::Transaction> |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
=back |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
=cut |
286
|
|
|
|
|
|
|
|