File Coverage

blib/lib/Bitcoin/Crypto/Transaction/Output.pm
Criterion Covered Total %
statement 29 29 100.0
branch n/a
condition n/a
subroutine 10 10 100.0
pod n/a
total 39 39 100.0


line stmt bran cond sub pod time code
1             package Bitcoin::Crypto::Transaction::Output;
2             $Bitcoin::Crypto::Transaction::Output::VERSION = '2.000_01'; # TRIAL
3             $Bitcoin::Crypto::Transaction::Output::VERSION = '2.00001';
4 9     9   113 use v5.10;
  9         42  
5 9     9   60 use strict;
  9         25  
  9         199  
6 9     9   49 use warnings;
  9         57  
  9         217  
7              
8 9     9   56 use Moo;
  9         37  
  9         75  
9 9     9   4375 use Mooish::AttributeBuilder -standard;
  9         33  
  9         83  
10 9     9   1407 use Type::Params -sigs;
  9         40  
  9         72  
11              
12 9     9   4484 use Bitcoin::Crypto::Types qw(Int BitcoinScript InstanceOf Object Str ByteStr PositiveOrZeroInt ScalarRef);
  9         28  
  9         66  
13 9     9   40926 use Bitcoin::Crypto::Helpers qw(pack_varint unpack_varint ensure_length); # loads BigInt
  9         45  
  9         641  
14 9     9   63 use Bitcoin::Crypto::Util qw(to_format);
  9         20  
  9         398  
15 9     9   60 use Bitcoin::Crypto::Exception;
  9         34  
  9         6051  
16              
17             has param 'value' => (
18             writer => 1,
19             coerce => (InstanceOf ['Math::BigInt'])
20             ->where(q{$_ >= 0})
21             ->plus_coercions(Int | Str, q{ Math::BigInt->new($_) }),
22             );
23              
24             has param 'locking_script' => (
25             coerce => BitcoinScript,
26             writer => 1,
27             );
28              
29             with qw(
30             Bitcoin::Crypto::Role::ShallowClone
31             );
32              
33             signature_for is_standard => (
34             method => Object,
35             positional => [],
36             );
37              
38             sub is_standard
39             {
40             my ($self) = @_;
41              
42             return $self->locking_script->has_type;
43             }
44              
45             signature_for set_max_value => (
46             method => Object,
47             positional => [],
48             );
49              
50             sub set_max_value
51             {
52             my ($self) = @_;
53              
54             $self->set_value('0xffffffffffffffff');
55             return $self;
56             }
57              
58             signature_for value_serialized => (
59             method => Object,
60             positional => [],
61             );
62              
63             sub value_serialized
64             {
65             my ($self) = @_;
66              
67             # NOTE: little endian
68             my $value = $self->value->as_bytes;
69             return scalar reverse ensure_length($value, 8);
70             }
71              
72             signature_for to_serialized => (
73             method => Object,
74             positional => [],
75             );
76              
77             sub to_serialized
78             {
79             my ($self) = @_;
80              
81             # output should be serialized as follows:
82             # - value, 8 bytes
83             # - locking script length, 1-9 bytes
84             # - locking script
85             my $serialized = '';
86              
87             $serialized .= $self->value_serialized;
88              
89             my $script = $self->locking_script->to_serialized;
90             $serialized .= pack_varint(length $script);
91             $serialized .= $script;
92              
93             return $serialized;
94             }
95              
96             signature_for from_serialized => (
97             method => Str,
98             head => [ByteStr],
99             named => [
100             pos => ScalarRef [PositiveOrZeroInt],
101             {optional => 1},
102             ],
103             );
104              
105             sub from_serialized
106             {
107             my ($class, $serialized, $args) = @_;
108             my $partial = $args->pos;
109             my $pos = $partial ? ${$args->pos} : 0;
110              
111             my $value = reverse substr $serialized, $pos, 8;
112             $pos += 8;
113              
114             my ($script_size_len, $script_size) = unpack_varint(substr $serialized, $pos, 9);
115             $pos += $script_size_len;
116              
117             Bitcoin::Crypto::Exception::Transaction->raise(
118             'serialized input script data is corrupted'
119             ) if $pos + $script_size > length $serialized;
120              
121             my $script = substr $serialized, $pos, $script_size;
122             $pos += $script_size;
123              
124             Bitcoin::Crypto::Exception::Transaction->raise(
125             'serialized output data is corrupted'
126             ) if !$partial && $pos != length $serialized;
127              
128             ${$args->pos} = $pos
129             if $partial;
130              
131             return $class->new(
132             value => Math::BigInt->from_bytes($value),
133             locking_script => $script,
134             );
135             }
136              
137             signature_for dump => (
138             method => Object,
139             named => [
140             ],
141             );
142              
143             sub dump
144             {
145             my ($self, $params) = @_;
146              
147             my $type = $self->locking_script->type // 'Custom';
148             my $address = $self->locking_script->get_address // '';
149             $address = " to $address" if $address;
150              
151             my @result;
152             push @result, "$type Output$address";
153             push @result, 'value: ' . $self->value;
154             push @result, 'locking script: ' . to_format [hex => $self->locking_script->to_serialized];
155              
156             return join "\n", @result;
157             }
158              
159             1;
160              
161             __END__
162             =head1 NAME
163              
164             Bitcoin::Crypto::Transaction::Output - Bitcoin transaction output instance
165              
166             =head1 SYNOPSIS
167              
168             use Bitcoin::Crypto qw(btc_transaction);
169              
170             my $tx = btc_transaction->new;
171              
172             $tx->add_output(
173             value => 1234,
174             locking_script => [P2WPKH => $my_address],
175             );
176              
177             print $tx->outputs->[0]->dump;
178              
179              
180             =head1 DESCRIPTION
181              
182             This is an output instance implementation used in transactions. It is rarely
183             interacted with directly.
184              
185             =head1 INTERFACE
186              
187             =head2 Attributes
188              
189             =head3 value
190              
191             Non-negative integer value of the output in the smallest unit (satoshi).
192             Required.
193              
194             I<Available in the constructor>.
195              
196             I<writer>: C<set_value>
197              
198             =head3 locking_script
199              
200             An instance of the script used to lock the coins. Required.
201              
202             Can be constructed from a standard script by passing an array reference with
203             script type and an address.
204              
205             I<Available in the constructor>.
206              
207             I<writer>: C<set_locking_script>
208              
209             =head2 Methods
210              
211             =head3 new
212              
213             $block = $class->new(%args)
214              
215             This is a standard Moo constructor, which can be used to create the object. It
216             takes arguments specified in L</Attributes>.
217              
218             Returns class instance.
219              
220             =head3 is_standard
221              
222             $boolean = $object->is_standard()
223              
224             Returns true if L</locking_script> is a standard script type.
225              
226             =head3 set_max_value
227              
228             $object = $object->set_max_value()
229              
230             Sets the max possible value for this output, as required by digests. Mostly
231             used internally.
232              
233             =head3 value_serialized
234              
235             $bytestring = $object->value_serialized()
236              
237             Returns the bytesting of serialized value ready to be included in a serialized
238             transaction or digest. Mostly used internally.
239              
240             =head3 to_serialized
241              
242             $bytestring = $object->to_serialized()
243              
244             Returns the serialized output data to be included into a serialized transaction.
245              
246             =head3 from_serialized
247              
248             $object = $class->from_serialized($bytestring, %params)
249              
250             Creates an object instance from serialized data.
251              
252             C<%params> can be any of:
253              
254             =over
255              
256             =item * C<pos>
257              
258             Position for partial string decoding. Optional. If passed, must be a scalar
259             reference to an integer value.
260              
261             This integer will mark the starting position of C<$bytestring> from which to
262             start decoding. It will be set to the next byte after end of output stream.
263              
264             =back
265              
266             =head3 dump
267              
268             $text = $object->dump()
269              
270             Returns a readable description of the output.
271              
272             =head1 EXCEPTIONS
273              
274             This module throws an instance of L<Bitcoin::Crypto::Exception> if it
275             encounters an error. It can produce the following error types from the
276             L<Bitcoin::Crypto::Exception> namespace:
277              
278             =over
279              
280             =item * Bitcoin::Crypto::Exception::Transaction - general error with transaction
281              
282             =back
283              
284             =head1 SEE ALSO
285              
286             =over
287              
288             =item L<Bitcoin::Crypto::Transaction>
289              
290             =item L<Bitcoin::Crypto::Transaction::UTXO>
291              
292             =back
293              
294             =cut
295