File Coverage

blib/lib/Bitcoin/Crypto/Exception.pm
Criterion Covered Total %
statement 131 139 94.2
branch 13 18 72.2
condition 0 3 0.0
subroutine 41 42 97.6
pod 5 5 100.0
total 190 207 91.7


line stmt bran cond sub pod time code
1             package Bitcoin::Crypto::Exception;
2             $Bitcoin::Crypto::Exception::VERSION = '2.000_01'; # TRIAL
3             $Bitcoin::Crypto::Exception::VERSION = '2.00001';
4 36     36   77010 use v5.10;
  36         149  
5 36     36   236 use strict;
  36         84  
  36         776  
6 36     36   199 use warnings;
  36         86  
  36         946  
7              
8 36     36   10313 use Moo;
  36         121698  
  36         307  
9 36     36   45667 use Mooish::AttributeBuilder -standard;
  36         34655  
  36         373  
10 36     36   19366 use Try::Tiny;
  36         38471  
  36         2390  
11 36     36   269 use Scalar::Util qw(blessed);
  36         110  
  36         1678  
12              
13 36     36   3427 use Bitcoin::Crypto::Types qw(Str Maybe ArrayRef);
  36         113  
  36         1284  
14              
15 36     36   146152 use namespace::clean;
  36         481125  
  36         259  
16              
17             use overload
18 36         424 q{""} => "as_string",
19 36     36   14363 fallback => 1;
  36         105  
20              
21             has param 'message' => (
22             isa => Str,
23             writer => -hidden,
24             );
25              
26             has field 'caller' => (
27             isa => Maybe [ArrayRef],
28             default => sub {
29             for my $call_level (1 .. 20) {
30             my ($package, $file, $line) = caller $call_level;
31             if (defined $package && $package !~ /^(Bitcoin::Crypto|Try::Tiny|Type::Coercion)/) {
32             return [$package, $file, $line];
33             }
34             }
35             return undef;
36             },
37             );
38              
39             sub raise
40             {
41 602     602 1 5332 my ($self, $error) = @_;
42              
43 602 100       1384 if (defined $error) {
44 548         12014 $self = $self->new(message => $error);
45             }
46              
47 602         27934 die $self;
48             }
49              
50             sub throw
51             {
52 1     1 1 524 goto \&raise;
53             }
54              
55             sub trap_into
56             {
57 1614     1614 1 6984 my ($class, $sub, $prefix) = @_;
58              
59 1614         2374 my $ret;
60             try {
61 1614     1614   115814 $ret = $sub->();
62             }
63             catch {
64 68     68   1309 my $ex = $_;
65              
66 68 100       332 if (blessed $ex) {
67 58 100       288 if ($ex->isa($class)) {
68 54 50       1401 $ex->_set_message("$prefix: " . $ex->message)
69             if $prefix;
70              
71 54         1483 $ex->raise;
72             }
73              
74 4 50       29 if ($ex->isa('Bitcoin::Crypto::Exception')) {
75 4 50       73 $class->raise(($prefix ? "$prefix: " : '') . $ex->message);
76             }
77             }
78              
79 10 100       120 $class->raise($prefix ? "$prefix: $ex" : "$ex");
80 1614         9339 };
81              
82 1546         359961 return $ret;
83             }
84              
85             sub as_string
86             {
87 9     9 1 6690 my ($self) = @_;
88              
89 9         295 my $raised = $self->message;
90 9         231 $raised =~ s/\s+\z//;
91              
92 9         46 my $caller = $self->caller;
93 9 100       39 if (defined $caller) {
94 7         38 $raised .= ' (raised at ' . $caller->[1] . ', line ' . $caller->[2] . ')';
95             }
96              
97 9         22 my $class = ref $self;
98 9         31 $class =~ s/Bitcoin::Crypto::Exception:://;
99              
100 9         88 return "An error occured in Bitcoin subroutines: [$class] $raised";
101             }
102              
103             {
104              
105             package Bitcoin::Crypto::Exception::Transaction;
106             $Bitcoin::Crypto::Exception::Transaction::VERSION = '2.000_01'; # TRIAL
107             $Bitcoin::Crypto::Exception::Transaction::VERSION = '2.00001';
108 36     36   43222 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         11079  
  36         253  
109              
110             }
111              
112             {
113              
114             package Bitcoin::Crypto::Exception::UTXO;
115             $Bitcoin::Crypto::Exception::UTXO::VERSION = '2.000_01'; # TRIAL
116             $Bitcoin::Crypto::Exception::UTXO::VERSION = '2.00001';
117 36     36   3320 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         106  
  36         180  
118              
119             }
120              
121             {
122              
123             package Bitcoin::Crypto::Exception::Sign;
124             $Bitcoin::Crypto::Exception::Sign::VERSION = '2.000_01'; # TRIAL
125             $Bitcoin::Crypto::Exception::Sign::VERSION = '2.00001';
126 36     36   3055 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         110  
  36         173  
127              
128             }
129              
130             {
131              
132             package Bitcoin::Crypto::Exception::Verify;
133             $Bitcoin::Crypto::Exception::Verify::VERSION = '2.000_01'; # TRIAL
134             $Bitcoin::Crypto::Exception::Verify::VERSION = '2.00001';
135 36     36   2886 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         165  
  36         209  
136             }
137              
138             {
139              
140             package Bitcoin::Crypto::Exception::KeyCreate;
141             $Bitcoin::Crypto::Exception::KeyCreate::VERSION = '2.000_01'; # TRIAL
142             $Bitcoin::Crypto::Exception::KeyCreate::VERSION = '2.00001';
143 36     36   3290 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         126  
  36         246  
144             }
145              
146             {
147              
148             package Bitcoin::Crypto::Exception::KeyDerive;
149             $Bitcoin::Crypto::Exception::KeyDerive::VERSION = '2.000_01'; # TRIAL
150             $Bitcoin::Crypto::Exception::KeyDerive::VERSION = '2.00001';
151 36     36   3183 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         115  
  36         210  
152             }
153              
154             {
155              
156             package Bitcoin::Crypto::Exception::MnemonicGenerate;
157             $Bitcoin::Crypto::Exception::MnemonicGenerate::VERSION = '2.000_01'; # TRIAL
158             $Bitcoin::Crypto::Exception::MnemonicGenerate::VERSION = '2.00001';
159 36     36   3216 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         114  
  36         364  
160             }
161              
162             {
163              
164             package Bitcoin::Crypto::Exception::MnemonicCheck;
165             $Bitcoin::Crypto::Exception::MnemonicCheck::VERSION = '2.000_01'; # TRIAL
166             $Bitcoin::Crypto::Exception::MnemonicCheck::VERSION = '2.00001';
167 36     36   3073 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         127  
  36         208  
168             }
169              
170             {
171              
172             package Bitcoin::Crypto::Exception::Base58InputFormat;
173             $Bitcoin::Crypto::Exception::Base58InputFormat::VERSION = '2.000_01'; # TRIAL
174             $Bitcoin::Crypto::Exception::Base58InputFormat::VERSION = '2.00001';
175 36     36   4078 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         126  
  36         230  
176             }
177              
178             {
179              
180             package Bitcoin::Crypto::Exception::Base58InputChecksum;
181             $Bitcoin::Crypto::Exception::Base58InputChecksum::VERSION = '2.000_01'; # TRIAL
182             $Bitcoin::Crypto::Exception::Base58InputChecksum::VERSION = '2.00001';
183 36     36   3053 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         120  
  36         239  
184             }
185              
186             {
187              
188             package Bitcoin::Crypto::Exception::Bech32InputFormat;
189             $Bitcoin::Crypto::Exception::Bech32InputFormat::VERSION = '2.000_01'; # TRIAL
190             $Bitcoin::Crypto::Exception::Bech32InputFormat::VERSION = '2.00001';
191 36     36   3107 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         76  
  36         165  
192             }
193              
194             {
195              
196             package Bitcoin::Crypto::Exception::Bech32InputData;
197             $Bitcoin::Crypto::Exception::Bech32InputData::VERSION = '2.000_01'; # TRIAL
198             $Bitcoin::Crypto::Exception::Bech32InputData::VERSION = '2.00001';
199 36     36   3069 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         92  
  36         201  
200             }
201              
202             {
203              
204             package Bitcoin::Crypto::Exception::Bech32InputChecksum;
205             $Bitcoin::Crypto::Exception::Bech32InputChecksum::VERSION = '2.000_01'; # TRIAL
206             $Bitcoin::Crypto::Exception::Bech32InputChecksum::VERSION = '2.00001';
207 36     36   3100 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         128  
  36         193  
208             }
209              
210             {
211              
212             package Bitcoin::Crypto::Exception::SegwitProgram;
213             $Bitcoin::Crypto::Exception::SegwitProgram::VERSION = '2.000_01'; # TRIAL
214             $Bitcoin::Crypto::Exception::SegwitProgram::VERSION = '2.00001';
215 36     36   3113 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         99  
  36         244  
216             }
217              
218             {
219              
220             package Bitcoin::Crypto::Exception::ScriptType;
221             $Bitcoin::Crypto::Exception::ScriptType::VERSION = '2.000_01'; # TRIAL
222             $Bitcoin::Crypto::Exception::ScriptType::VERSION = '2.00001';
223 36     36   3271 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         137  
  36         434  
224             }
225              
226             {
227              
228             package Bitcoin::Crypto::Exception::ScriptOpcode;
229             $Bitcoin::Crypto::Exception::ScriptOpcode::VERSION = '2.000_01'; # TRIAL
230             $Bitcoin::Crypto::Exception::ScriptOpcode::VERSION = '2.00001';
231 36     36   3286 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         126  
  36         246  
232             }
233              
234             {
235              
236             package Bitcoin::Crypto::Exception::ScriptPush;
237             $Bitcoin::Crypto::Exception::ScriptPush::VERSION = '2.000_01'; # TRIAL
238             $Bitcoin::Crypto::Exception::ScriptPush::VERSION = '2.00001';
239 36     36   3157 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         89  
  36         243  
240             }
241              
242             {
243              
244             package Bitcoin::Crypto::Exception::ScriptSyntax;
245             $Bitcoin::Crypto::Exception::ScriptSyntax::VERSION = '2.000_01'; # TRIAL
246             $Bitcoin::Crypto::Exception::ScriptSyntax::VERSION = '2.00001';
247 36     36   2840 use Moo;
  36         98  
  36         362  
248 36     36   16516 use Mooish::AttributeBuilder -standard;
  36         112  
  36         335  
249 36     36   4828 use Bitcoin::Crypto::Types qw(PositiveOrZeroInt ArrayRef);
  36         80  
  36         373  
250              
251             extends 'Bitcoin::Crypto::Exception';
252              
253             has field 'script' => (
254             isa => ArrayRef,
255             writer => 1,
256             predicate => 1,
257             );
258              
259             has field 'error_position' => (
260             isa => PositiveOrZeroInt,
261             writer => 1,
262             predicate => 1,
263             );
264              
265             sub as_string
266             {
267 0     0 1   my ($self) = @_;
268 0           my $message = $self->SUPER::as_string;
269              
270 0 0 0       if ($self->has_script && $self->has_error_position) {
271 0           my @script = @{$self->script};
  0            
272 0           $script[$self->error_position] = '> ' . $script[$self->error_position] . ' <-- here';
273 0           $message .= "\n" . join ' ', @script;
274             }
275              
276 0           return $message;
277             }
278             }
279              
280             {
281              
282             package Bitcoin::Crypto::Exception::ScriptRuntime;
283             $Bitcoin::Crypto::Exception::ScriptRuntime::VERSION = '2.000_01'; # TRIAL
284             $Bitcoin::Crypto::Exception::ScriptRuntime::VERSION = '2.00001';
285 36     36   95014 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         130  
  36         246  
286             }
287              
288             {
289              
290             package Bitcoin::Crypto::Exception::TransactionScript;
291             $Bitcoin::Crypto::Exception::TransactionScript::VERSION = '2.000_01'; # TRIAL
292             $Bitcoin::Crypto::Exception::TransactionScript::VERSION = '2.00001';
293 36         237 use parent -norequire,
294             'Bitcoin::Crypto::Exception::Transaction',
295 36     36   4687 'Bitcoin::Crypto::Exception::ScriptRuntime';
  36         170  
296             }
297              
298             {
299              
300             package Bitcoin::Crypto::Exception::NetworkCheck;
301             $Bitcoin::Crypto::Exception::NetworkCheck::VERSION = '2.000_01'; # TRIAL
302             $Bitcoin::Crypto::Exception::NetworkCheck::VERSION = '2.00001';
303 36     36   3483 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         98  
  36         179  
304             }
305              
306             {
307              
308             package Bitcoin::Crypto::Exception::NetworkConfig;
309             $Bitcoin::Crypto::Exception::NetworkConfig::VERSION = '2.000_01'; # TRIAL
310             $Bitcoin::Crypto::Exception::NetworkConfig::VERSION = '2.00001';
311 36     36   3267 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         136  
  36         222  
312             }
313              
314             {
315              
316             package Bitcoin::Crypto::Exception::AddressGenerate;
317             $Bitcoin::Crypto::Exception::AddressGenerate::VERSION = '2.000_01'; # TRIAL
318             $Bitcoin::Crypto::Exception::AddressGenerate::VERSION = '2.00001';
319 36     36   3058 use parent -norequire, 'Bitcoin::Crypto::Exception';
  36         94  
  36         229  
320             }
321              
322             1;
323              
324             __END__
325             =head1 NAME
326              
327             Bitcoin::Crypto::Exception - Internal exception classes for Bitcoin::Crypto
328              
329             =head1 SYNOPSIS
330              
331             try {
332             decode_segwit('Not a segwit address');
333             }
334             catch ($error) {
335             # $error is an instance of Bitcoin::Crypto::Exception and stringifies automatically
336             warn "$error";
337              
338             # it also contains some information about the problem to avoid regex matching
339             if ($error->isa('Bitcoin::Crypto::Exception::Bech32InputFormat')) {
340             log $error->message;
341             }
342             }
343              
344             =head1 DESCRIPTION
345              
346             An exception wrapper class with automatic stringification and standarized
347             raising.
348              
349             Contains inline packages that identify parts that went wrong (like
350             C<Bitcoin::Crypto::Exception::Sign> for errors in signature generation). Search
351             individual Bitcoin::Crypto packages documentation for a list the exception
352             classes to check for extra control flow when needed.
353              
354             =head1 INTERFACE
355              
356             =head2 Attributes
357              
358             =head3 message
359              
360             The wrapped error message (a string). Note: this is the raw message,
361             not the serialized form like in L</as_string>.
362              
363             =head3 caller
364              
365             B<Not assignable in the constructor>
366              
367             An array ref containing: package name, file name and line number (same
368             as C<[caller()]> perl expression). It will point to the first place from
369             outside Bitcoin::Crypto which called it. May be undefined if it cannot find a
370             calling source.
371              
372             =head2 Methods
373              
374             =head3 new
375              
376             $runner = Bitcoin::Crypto::Exception->new(%data)
377              
378             This is a standard Moo constructor, which can be used to create the object. It
379             takes arguments specified in L</Attributes>. For exceptions, it's probably
380             better to use L</raise> instead.
381              
382             Returns class instance.
383              
384             =head3 as_string
385              
386             $error_info = $object->as_string()
387              
388             Stringifies the error, using the L</message> method, L</caller> method and some
389             extra text for context.
390              
391             =head3 raise
392              
393             $object->raise()
394             $class->raise($message)
395              
396             Creates a new instance and throws it. If used on an object, throws it right away.
397              
398             try {
399             # throws, but will be catched
400             Bitcoin::Crypto::Exception->raise('something went wrong');
401             }
402             catch ($exception) {
403             # throws again
404             $exception->raise;
405             }
406              
407             =head3 throw
408              
409             An alias to C<raise>.
410              
411             =head3 trap_into
412              
413             $sub_result = $class->trap_into($sub, $prefix)
414              
415             Executes the given subroutine in an exception-trapping environment. Any
416             exceptions thrown inside the subroutine C<$sub> will be re-thrown after turning
417             them into objects of the given C<::Exception> class. If no exception is thrown,
418             method returns the value returned by C<$sub>.
419              
420             my $result = Bitcoin::Crypto::Exception->trap_into(sub {
421             die 'something went wrong';
422             });
423              
424             C<$prefix> can be specified to better format the message.
425