File Coverage

blib/lib/Bitcoin/Crypto/Exception.pm
Criterion Covered Total %
statement 98 98 100.0
branch 7 10 70.0
condition n/a
subroutine 29 29 100.0
pod 4 4 100.0
total 138 141 97.8


line stmt bran cond sub pod time code
1             package Bitcoin::Crypto::Exception;
2             $Bitcoin::Crypto::Exception::VERSION = '1.008';
3 19     19   145722 use v5.10;
  19         119  
4 19     19   117 use strict;
  19         35  
  19         412  
5 19     19   93 use warnings;
  19         74  
  19         540  
6 19     19   5492 use Moo;
  19         73120  
  19         122  
7 19     19   25359 use Types::Standard qw(Maybe Str ArrayRef);
  19         1065450  
  19         198  
8              
9 19     19   56199 use namespace::clean;
  19         296291  
  19         146  
10              
11             use overload
12 19         181 q{""} => "as_string",
13 19     19   6456 fallback => 1;
  19         49  
14              
15             has 'message' => (
16             is => 'ro',
17             isa => Str,
18             required => 1,
19             );
20              
21             has 'caller' => (
22             is => 'ro',
23             isa => Maybe [ArrayRef],
24             default => sub {
25             for my $call_level (1 .. 10) {
26             my ($package, $file, $line) = caller $call_level;
27             if (defined $package && $package !~ /^Bitcoin::Crypto/) {
28             return [$package, $file, $line];
29             }
30             }
31             return undef;
32             },
33             init_arg => undef,
34             );
35              
36             sub raise
37             {
38 66     66 1 801 my ($self, $error) = @_;
39              
40 66 50       185 unless (ref $self) {
41 66         1523 $self = $self->new(message => $error);
42             }
43              
44 66         4283 die $self;
45             }
46              
47             sub throw
48             {
49 6     6 1 559 goto \&raise;
50             }
51              
52             sub trap_into
53             {
54 553     553 1 2440 my ($class, $sub) = @_;
55              
56             # make sure we use class name
57 553 50       1365 $class = ref $class
58             if ref $class;
59              
60 553         775 my $ret;
61 553         793 my $error = do {
62 553         919 local $@;
63 553         1082 my $failure = not eval {
64 553         1274 $ret = $sub->();
65 548         306095 return 1;
66             };
67              
68 553 100       3238 $@ || $failure;
69             };
70              
71 553 100       1423 if ($error) {
72              
73             # make sure we stringify the error
74 5         34 $class->throw("$error");
75             }
76              
77 548         1743 return $ret;
78             }
79              
80             sub as_string
81             {
82 5     5 1 2145 my ($self) = @_;
83              
84 5         26 my $raised = $self->message;
85 5         37 $raised =~ s/\s$//g;
86 5         20 my $caller = $self->caller;
87 5 50       16 if (defined $caller) {
88 5         22 $raised .= ' (raised at ' . $caller->[1] . ', line ' . $caller->[2] . ')';
89             }
90 5         32 return 'An error occured in Bitcoin subroutines: ' . $raised;
91             }
92              
93             {
94              
95             package Bitcoin::Crypto::Exception::Sign;
96             $Bitcoin::Crypto::Exception::Sign::VERSION = '1.008';
97 19     19   20498 use parent -norequire, "Bitcoin::Crypto::Exception";
  19         5919  
  19         163  
98              
99             }
100              
101             {
102              
103             package Bitcoin::Crypto::Exception::Verify;
104             $Bitcoin::Crypto::Exception::Verify::VERSION = '1.008';
105 19     19   1763 use parent -norequire, "Bitcoin::Crypto::Exception";
  19         51  
  19         93  
106             }
107              
108             {
109              
110             package Bitcoin::Crypto::Exception::KeyCreate;
111             $Bitcoin::Crypto::Exception::KeyCreate::VERSION = '1.008';
112 19     19   1449 use parent -norequire, "Bitcoin::Crypto::Exception";
  19         55  
  19         94  
113             }
114              
115             {
116              
117             package Bitcoin::Crypto::Exception::KeyDerive;
118             $Bitcoin::Crypto::Exception::KeyDerive::VERSION = '1.008';
119 19     19   1440 use parent -norequire, "Bitcoin::Crypto::Exception";
  19         41  
  19         102  
120             }
121              
122             {
123              
124             package Bitcoin::Crypto::Exception::MnemonicGenerate;
125             $Bitcoin::Crypto::Exception::MnemonicGenerate::VERSION = '1.008';
126 19     19   1852 use parent -norequire, "Bitcoin::Crypto::Exception";
  19         51  
  19         87  
127             }
128              
129             {
130              
131             package Bitcoin::Crypto::Exception::MnemonicCheck;
132             $Bitcoin::Crypto::Exception::MnemonicCheck::VERSION = '1.008';
133 19     19   1650 use parent -norequire, "Bitcoin::Crypto::Exception";
  19         49  
  19         112  
134             }
135              
136             {
137              
138             package Bitcoin::Crypto::Exception::Base58InputFormat;
139             $Bitcoin::Crypto::Exception::Base58InputFormat::VERSION = '1.008';
140 19     19   1653 use parent -norequire, "Bitcoin::Crypto::Exception";
  19         112  
  19         123  
141             }
142              
143             {
144              
145             package Bitcoin::Crypto::Exception::Base58InputChecksum;
146             $Bitcoin::Crypto::Exception::Base58InputChecksum::VERSION = '1.008';
147 19     19   1821 use parent -norequire, "Bitcoin::Crypto::Exception";
  19         99  
  19         102  
148             }
149              
150             {
151              
152             package Bitcoin::Crypto::Exception::Bech32InputFormat;
153             $Bitcoin::Crypto::Exception::Bech32InputFormat::VERSION = '1.008';
154 19     19   1668 use parent -norequire, "Bitcoin::Crypto::Exception";
  19         74  
  19         128  
155             }
156              
157             {
158              
159             package Bitcoin::Crypto::Exception::Bech32InputData;
160             $Bitcoin::Crypto::Exception::Bech32InputData::VERSION = '1.008';
161 19     19   1628 use parent -norequire, "Bitcoin::Crypto::Exception";
  19         53  
  19         112  
162             }
163              
164             {
165              
166             package Bitcoin::Crypto::Exception::Bech32Type;
167             $Bitcoin::Crypto::Exception::Bech32Type::VERSION = '1.008';
168 19     19   1659 use parent -norequire, "Bitcoin::Crypto::Exception";
  19         52  
  19         110  
169             }
170              
171             {
172              
173             package Bitcoin::Crypto::Exception::Bech32InputChecksum;
174             $Bitcoin::Crypto::Exception::Bech32InputChecksum::VERSION = '1.008';
175 19     19   1645 use parent -norequire, "Bitcoin::Crypto::Exception";
  19         56  
  19         95  
176             }
177              
178             {
179              
180             package Bitcoin::Crypto::Exception::SegwitProgram;
181             $Bitcoin::Crypto::Exception::SegwitProgram::VERSION = '1.008';
182 19     19   1637 use parent -norequire, "Bitcoin::Crypto::Exception";
  19         72  
  19         95  
183             }
184              
185             {
186              
187             package Bitcoin::Crypto::Exception::ValidationTest;
188             $Bitcoin::Crypto::Exception::ValidationTest::VERSION = '1.008';
189 19     19   2199 use parent -norequire, "Bitcoin::Crypto::Exception";
  19         55  
  19         94  
190             }
191              
192             {
193              
194             package Bitcoin::Crypto::Exception::ScriptOpcode;
195             $Bitcoin::Crypto::Exception::ScriptOpcode::VERSION = '1.008';
196 19     19   1572 use parent -norequire, "Bitcoin::Crypto::Exception";
  19         100  
  19         113  
197             }
198              
199             {
200              
201             package Bitcoin::Crypto::Exception::ScriptPush;
202             $Bitcoin::Crypto::Exception::ScriptPush::VERSION = '1.008';
203 19     19   1686 use parent -norequire, "Bitcoin::Crypto::Exception";
  19         63  
  19         81  
204             }
205              
206             {
207              
208             package Bitcoin::Crypto::Exception::NetworkConfig;
209             $Bitcoin::Crypto::Exception::NetworkConfig::VERSION = '1.008';
210 19     19   1836 use parent -norequire, "Bitcoin::Crypto::Exception";
  19         54  
  19         114  
211             }
212              
213             {
214              
215             package Bitcoin::Crypto::Exception::AddressGenerate;
216             $Bitcoin::Crypto::Exception::AddressGenerate::VERSION = '1.008';
217 19     19   1658 use parent -norequire, "Bitcoin::Crypto::Exception";
  19         65  
  19         117  
218             }
219              
220             1;
221              
222             __END__
223             =head1 NAME
224              
225             Bitcoin::Crypto::Exception - Exception class for Bitcoin::Crypto purposes
226              
227             =head1 SYNOPSIS
228              
229             use Try::Tiny;
230              
231             try {
232             decode_segwit("Not a segwit address");
233             } catch {
234             my $error = $_;
235              
236             # $error is an instance of Bitcoin::Crypto::Exception and stringifies automatically
237             warn "$error";
238              
239             # but also contains some information about the problem to avoid regex matching
240             if ($error->isa("Bitcoin::Crypto::Exception::Bech32InputFormat")) {
241             log $error->message;
242             }
243             };
244              
245             =head1 DESCRIPTION
246              
247             A wrapper class with automatic stringification and standarized raising.
248             Contains many other inline packages that identify parts that went wrong (like Bitcoin::Crypto::Exception::Sign for errors in signature generation).
249             See individual Bitcoin::Crypto packages documentation to see the exception classes to check for extra control flow when needed.
250              
251             =head1 FUNCTIONS
252              
253             =head2 message
254              
255             $error_string = $object->message()
256              
257             Returns the error message (a string).
258              
259             =head2 caller
260              
261             $caller_aref = $object->caller()
262              
263             Returns an array ref containing: package name, file name and line number (same as C<[caller()]> perl expression). It will contain the data for the first code from outside Bitcoin::Crypto which called it. May be undefined if it cannot find a calling source.
264              
265             =head2 as_string
266              
267             $error_info = $object->as_string()
268              
269             Stringifies the error, using the C<message> method, C<caller> method and some extra text for context.
270              
271             =head2 raise
272              
273             $object->raise()
274             $class->raise($message)
275              
276             Creates a new instance and throws it. If used on an object, throws it right away.
277              
278             use Try::Tiny;
279              
280             try {
281             # throws, but will be catched
282             Bitcoin::Crypto::Exception->raise("something went wrong");
283             } catch {
284             my $exception = $_;
285              
286             # throws again
287             $exception->raise;
288             };
289              
290             =head2 throw
291              
292             An alias to C<raise>.
293              
294             =head2 trap_into
295              
296             $sub_result = $class->trap_into($sub)
297              
298             Executes the subroutine given as the only parameter inside an C<eval>. Any exceptions thrown inside the subroutine C<$sub> will be re-thrown after turning them into objects of the given class. If no exception is thrown, method returns the value returned by C<$sub>.
299              
300             my $result = Bitcoin::Crypto::Exception->trap_into(sub {
301             die "something went wrong";
302             });
303              
304             =cut
305