File Coverage

blib/lib/Bitcoin/Crypto/Transaction/Input.pm
Criterion Covered Total %
statement 60 60 100.0
branch 6 6 100.0
condition 1 2 50.0
subroutine 17 17 100.0
pod n/a
total 84 85 98.8


line stmt bran cond sub pod time code
1             package Bitcoin::Crypto::Transaction::Input;
2             $Bitcoin::Crypto::Transaction::Input::VERSION = '2.000_01'; # TRIAL
3             $Bitcoin::Crypto::Transaction::Input::VERSION = '2.00001';
4 29     29   398 use v5.10;
  29         117  
5 29     29   172 use strict;
  29         93  
  29         701  
6 29     29   157 use warnings;
  29         94  
  29         788  
7              
8 29     29   195 use Moo;
  29         74  
  29         220  
9 29     29   11532 use Mooish::AttributeBuilder -standard;
  29         118  
  29         225  
10 29     29   3641 use Type::Params -sigs;
  29         82  
  29         265  
11              
12 29     29   13705 use Bitcoin::Crypto qw(btc_utxo btc_script);
  29         73  
  29         1360  
13 29     29   211 use Bitcoin::Crypto::Constants;
  29         95  
  29         798  
14 29     29   178 use Bitcoin::Crypto::Helpers qw(pack_varint unpack_varint);
  29         77  
  29         1575  
15 29     29   1210 use Bitcoin::Crypto::Util qw(to_format);
  29         89  
  29         1451  
16             use Bitcoin::Crypto::Types
17 29     29   184 qw(ByteStr Str IntMaxBits ArrayRef InstanceOf Object BitcoinScript Bool Defined ScalarRef PositiveOrZeroInt);
  29         97  
  29         260  
18 29     29   139534 use Bitcoin::Crypto::Exception;
  29         115  
  29         767  
19 29     29   12701 use Bitcoin::Crypto::Script::Common;
  29         116  
  29         32390  
20              
21             has param 'utxo' => (
22             coerce => (InstanceOf ['Bitcoin::Crypto::Transaction::UTXO'])
23             ->plus_coercions(ArrayRef, q{ Bitcoin::Crypto::Transaction::UTXO->get(@$_) })
24             );
25              
26             has param 'signature_script' => (
27             writer => 1,
28             coerce => BitcoinScript,
29             default => '',
30             );
31              
32             has param 'sequence_no' => (
33             isa => IntMaxBits [32],
34             writer => 1,
35             default => Bitcoin::Crypto::Constants::max_sequence_no,
36             );
37              
38             has option 'witness' => (
39             coerce => ArrayRef [ByteStr],
40             writer => 1,
41             );
42              
43             with qw(
44             Bitcoin::Crypto::Role::ShallowClone
45             );
46              
47             sub _nested_script
48             {
49 82     82   175 my ($self) = @_;
50              
51 82         321 my $input_script = $self->signature_script->to_serialized;
52 82 100       270 return undef unless length $input_script;
53              
54 81         239 my $push = substr $input_script, 0, 1, '';
55 81 100       232 return undef unless ord $push == length $input_script;
56              
57 72         222 my $real_script = btc_script->from_serialized($input_script);
58 72         212 return $real_script;
59             }
60              
61             # script code for segwit digests (see script_base)
62             sub _script_code
63             {
64 46     46   108 my ($self) = @_;
65 46         130 my $utxo = $self->utxo;
66              
67 46         156 my $locking_script = $utxo->output->locking_script;
68 46         91 my $program;
69             my %types = (
70             P2WPKH => sub {
71              
72             # get script hash from P2WPKH (ignore the first two OPs - version and push)
73 15     15   70 my $hash = substr $locking_script->to_serialized, 2;
74 15         111 $program = Bitcoin::Crypto::Script::Common->new(PKH => $hash);
75             },
76             P2WSH => sub {
77              
78             # TODO: this is not complete, as it does not take OP_CODESEPARATORs into account
79             # NOTE: Transaction::Digest sets witness to signing_subscript
80 31   50 31   126 $program = btc_script->from_serialized(($self->witness // [''])->[-1]);
81             },
82 46         410 );
83              
84 46         946 my $type = $utxo->output->locking_script->type;
85              
86 46 100       472 if ($type eq 'P2SH') {
87              
88             # nested - nothing should get here without checking if nested script is native segwit
89 24         94 my $nested = $self->_nested_script;
90 24         423 $type = $nested->type;
91              
92 24         617 $locking_script = $nested;
93             }
94              
95 46         190 $types{$type}->();
96 46         536 return $program;
97             }
98              
99             signature_for to_serialized => (
100             method => Object,
101             positional => [
102             ],
103             );
104              
105             sub to_serialized
106             {
107             my ($self) = @_;
108              
109             # input should be serialized as follows:
110             # - transaction hash, 32 bytes
111             # - transaction output index, 4 bytes
112             # - signature script length, 1-9 bytes
113             # - signature script
114             # - sequence number, 4 bytes
115             my $serialized = '';
116              
117             $serialized .= $self->prevout;
118              
119             my $script = $self->signature_script->to_serialized;
120             $serialized .= pack_varint(length $script);
121             $serialized .= $script;
122              
123             $serialized .= pack 'V', $self->sequence_no;
124              
125             return $serialized;
126             }
127              
128             signature_for from_serialized => (
129             method => Str,
130             head => [ByteStr],
131             named => [
132             pos => ScalarRef [PositiveOrZeroInt],
133             {optional => 1},
134             ],
135             );
136              
137             sub from_serialized
138             {
139             my ($class, $serialized, $args) = @_;
140             my $partial = $args->pos;
141             my $pos = $partial ? ${$args->pos} : 0;
142              
143             my $transaction_hash = scalar reverse substr $serialized, $pos, 32;
144             $pos += 32;
145              
146             my $transaction_output_index = unpack 'V', substr $serialized, $pos, 4;
147             $pos += 4;
148              
149             my ($script_size_len, $script_size) = unpack_varint(substr $serialized, $pos, 9);
150             $pos += $script_size_len;
151              
152             Bitcoin::Crypto::Exception::Transaction->raise(
153             'serialized input script data is corrupted'
154             ) if $pos + $script_size > length $serialized;
155              
156             my $script = substr $serialized, $pos, $script_size;
157             $pos += $script_size;
158              
159             my $sequence = unpack 'V', substr $serialized, $pos, 4;
160             $pos += 4;
161              
162             Bitcoin::Crypto::Exception::Transaction->raise(
163             'serialized input data is corrupted'
164             ) if !$partial && $pos != length $serialized;
165              
166             ${$args->pos} = $pos
167             if $partial;
168              
169             return $class->new(
170             utxo => [$transaction_hash, $transaction_output_index],
171             signature_script => $script,
172             sequence_no => $sequence,
173             );
174             }
175              
176             signature_for is_segwit => (
177             method => Object,
178             positional => [],
179             );
180              
181             sub is_segwit
182             {
183             my ($self) = @_;
184              
185             # Determines whether this script is segwit (including nested variants).
186             # There's no need to verify P2SH hash matching, as it will be checked at a
187             # later stage. It's enough if the input promises the segwit format.
188              
189             my $output_script = $self->utxo->output->locking_script;
190             return !!1 if $output_script->is_native_segwit;
191             return !!0 unless ($output_script->type // '') eq 'P2SH';
192              
193             my $nested = $self->_nested_script;
194             return !!0 unless defined $nested;
195             return !!1 if $nested->is_native_segwit;
196              
197             return !!0;
198             }
199              
200             signature_for prevout => (
201             method => Object,
202             positional => [],
203             );
204              
205             sub prevout
206             {
207             my ($self) = @_;
208             my $utxo = $self->utxo;
209              
210             return scalar reverse($utxo->txid) . pack 'V', $utxo->output_index;
211             }
212              
213             signature_for script_base => (
214             method => Object,
215             positional => [],
216             );
217              
218             sub script_base
219             {
220             my ($self) = @_;
221              
222             if ($self->is_segwit) {
223             return $self->_script_code;
224             }
225             else {
226             return $self->utxo->output->locking_script;
227             }
228             }
229              
230             signature_for dump => (
231             method => Object,
232             named => [
233             ],
234             );
235              
236             sub dump
237             {
238             my ($self, $params) = @_;
239              
240             my $type = $self->utxo->output->locking_script->type // 'Custom';
241             my $address = $self->utxo->output->locking_script->get_address;
242             $address = " from $address" if $address;
243              
244             my @result;
245             push @result, "$type Input$address";
246             push @result, 'spending output #' . $self->utxo->output_index . ' from ' . to_format([hex => $self->utxo->txid]);
247             push @result, 'value: ' . $self->utxo->output->value;
248             push @result, sprintf 'sequence: 0x%X', $self->sequence_no;
249             push @result, 'locking script: ' . to_format [hex => $self->utxo->output->locking_script->to_serialized];
250              
251             if (!$self->signature_script->is_empty) {
252             push @result, 'signature script: ' . to_format [hex => $self->signature_script->to_serialized];
253             }
254              
255             if ($self->has_witness) {
256             push @result, 'witness: ';
257             foreach my $witness (@{$self->witness}) {
258             push @result, to_format [hex => $witness];
259             }
260             }
261              
262             return join "\n", @result;
263             }
264              
265             1;
266              
267             __END__
268             =head1 NAME
269              
270             Bitcoin::Crypto::Transaction::Input - Bitcoin transaction input instance
271              
272             =head1 SYNOPSIS
273              
274             use Bitcoin::Crypto qw(btc_transaction);
275              
276             my $tx = btc_transaction->new;
277              
278             $tx->add_input(
279             utxo => [$txid, $output_index],
280             );
281              
282             print $tx->inputs->[0]->dump;
283              
284              
285             =head1 DESCRIPTION
286              
287             This is an input instance implementation used in transactions. It is rarely
288             interacted with directly.
289              
290             =head1 INTERFACE
291              
292             =head2 Attributes
293              
294             =head3 utxo
295              
296             An instance of L<Bitcoin::Crypto::Transaction::UTXO>. Required.
297              
298             Can also be passed an array reference of two parameters, which will be fed to
299             L<Bitcoin::Crypto::Transaction::UTXO/get> to fetch the UTXO instance.
300              
301             I<Available in the constructor>.
302              
303             =head3 signature_script
304              
305             The script used to unlock the coins from the UTXO.
306              
307             By default, it is an empty script.
308              
309             I<Available in the constructor>.
310              
311             I<writer>: C<set_signature_script>
312              
313             =head3 sequence_no
314              
315             Also known as C<nSequence> in Bitcoin Core. The sequence number used in various
316             applications. Non-negative integer.
317              
318             By default, it is set to C<0xffffffff> (C<max_sequence_no> in C<Bitcoin::Crypto::Constants>).
319              
320             I<Available in the constructor>.
321              
322             I<writer>: C<set_sequence_no>
323              
324             =head3 witness
325              
326             SegWit data for this input. It is an array reference of bytestrings. Note that
327             each element in the witness must be a separate element in this array
328             (concatenating the witness into one bytestring will not work as intended).
329              
330             Empty by default.
331              
332             I<Available in the constructor>.
333              
334             I<writer>: C<set_witness>
335              
336             I<predicate>: C<has_witness>
337              
338             =head2 Methods
339              
340             =head3 new
341              
342             $block = $class->new(%args)
343              
344             This is a standard Moo constructor, which can be used to create the object. It
345             takes arguments specified in L</Attributes>.
346              
347             Returns class instance.
348              
349             =head3 to_serialized
350              
351             $bytestring = $object->to_serialized()
352              
353             Returns the serialized input data to be included into a serialized transaction.
354              
355             NOTE: serialized input does not include witness data, which is a part of this class.
356              
357             =head3 from_serialized
358              
359             $object = $class->from_serialized($bytestring, %params)
360              
361             Creates an object instance from serialized data.
362              
363             C<%params> can be any of:
364              
365             =over
366              
367             =item * C<pos>
368              
369             Position for partial string decoding. Optional. If passed, must be a scalar
370             reference to an integer value.
371              
372             This integer will mark the starting position of C<$bytestring> from which to
373             start decoding. It will be set to the next byte after end of input stream.
374              
375             =back
376              
377             =head3 is_segwit
378              
379             $boolean = $object->is_segwit()
380              
381             Returns true if this input represents a segwit output.
382              
383             For scripts which have C<signature_script> filled out, this method is able to
384             detect both native and compatibility segwit outputs (unlike
385             L<Bitcoin::Crypto::Script/is_native_segwit>).
386              
387             =head3 prevout
388              
389             $bytestring = $object->prevout()
390              
391             Returns a bytestring with prevout data ready to be encoded in places like
392             digest preimages. Mostly used internally.
393              
394             =head3 script_base
395              
396             $script = $object->script_base()
397              
398             Returns a base script for the digest. Mostly used internally.
399              
400             =head3 dump
401              
402             $text = $object->dump()
403              
404             Returns a readable description of the input.
405              
406             =head1 EXCEPTIONS
407              
408             This module throws an instance of L<Bitcoin::Crypto::Exception> if it
409             encounters an error. It can produce the following error types from the
410             L<Bitcoin::Crypto::Exception> namespace:
411              
412             =over
413              
414             =item * Bitcoin::Crypto::Exception::Transaction - general error with transaction
415              
416             =back
417              
418             =head1 SEE ALSO
419              
420             =over
421              
422             =item L<Bitcoin::Crypto::Transaction>
423              
424             =item L<Bitcoin::Crypto::Transaction::UTXO>
425              
426             =back
427              
428             =cut
429