File Coverage

blib/lib/Bitcoin/Crypto/Network.pm
Criterion Covered Total %
statement 47 47 100.0
branch 7 12 58.3
condition 2 3 66.6
subroutine 14 14 100.0
pod 5 5 100.0
total 75 81 92.5


line stmt bran cond sub pod time code
1             package Bitcoin::Crypto::Network;
2             $Bitcoin::Crypto::Network::VERSION = '1.008_01'; # TRIAL
3             $Bitcoin::Crypto::Network::VERSION = '1.00801';
4 12     12   142400 use v5.10;
  12         78  
5 12     12   79 use strict;
  12         26  
  12         298  
6 12     12   66 use warnings;
  12         34  
  12         352  
7 12     12   1761 use Moo;
  12         22333  
  12         142  
8 12     12   8985 use Scalar::Util qw(blessed);
  12         93  
  12         720  
9 12     12   1487 use Mooish::AttributeBuilder -standard;
  12         5584  
  12         110  
10              
11 12     12   2966 use Bitcoin::Crypto::Exception;
  12         45  
  12         437  
12 12     12   82 use Bitcoin::Crypto::Types qw(Str StrLength Int);
  12         42  
  12         109  
13              
14 12     12   32752 use namespace::clean;
  12         36  
  12         118  
15              
16             my %networks;
17             my $default_network;
18              
19             has param 'id' => (
20             isa => Str,
21             );
22              
23             has param 'name' => (
24             isa => Str,
25             );
26              
27             has param 'p2pkh_byte' => (
28             isa => StrLength [1, 1],
29             );
30              
31             has param 'wif_byte' => (
32             isa => StrLength [1, 1],
33             );
34              
35             has param 'p2sh_byte' => (
36             isa => StrLength [1, 1],
37             required => 0,
38             );
39              
40             has param 'segwit_hrp' => (
41             isa => Str,
42             required => 0,
43             );
44              
45             has param 'extprv_version' => (
46             isa => Int,
47             required => 0,
48             );
49              
50             has param 'extpub_version' => (
51             isa => Int,
52             required => 0,
53             );
54              
55             has param 'extprv_compat_version' => (
56             isa => Int,
57             required => 0,
58             );
59              
60             has param 'extpub_compat_version' => (
61             isa => Int,
62             required => 0,
63             );
64              
65             has param 'extprv_segwit_version' => (
66             isa => Int,
67             required => 0,
68             );
69              
70             has param 'extpub_segwit_version' => (
71             isa => Int,
72             required => 0,
73             );
74              
75             has param 'bip44_coin' => (
76             isa => Int,
77             required => 0,
78             );
79              
80             sub register
81             {
82 50     50 1 370 my ($self, %config) = @_;
83 50 50       192 if (!blessed $self) {
84 50         976 $self = $self->new(%config);
85             }
86 49         104115 $networks{$self->id} = $self;
87 49         179 return $self;
88             }
89              
90             sub set_default
91             {
92 13     13 1 39 my ($self) = @_;
93              
94 13 50       98 Bitcoin::Crypto::Exception::NetworkConfig->raise(
95             'network must be an instance of Bitcoin::Crypto::Network'
96             ) unless blessed($self);
97              
98             Bitcoin::Crypto::Exception::NetworkConfig->raise(
99             'the network needs to be registered before becoming the default one'
100 13 50       79 ) unless defined $networks{$self->id};
101              
102 13         43 $default_network = $self->id;
103 13         29 return $self;
104             }
105              
106             sub supports_segwit
107             {
108 34     34 1 76 my ($self) = @_;
109              
110 34         163 return defined $self->segwit_hrp;
111             }
112              
113             sub find
114             {
115 57     57 1 2495 my ($class, $sub) = @_;
116              
117 57 100       164 return keys %networks
118             unless defined $sub;
119              
120 54 50       169 Bitcoin::Crypto::Exception::NetworkConfig->raise(
121             'argument passed to Bitcoin::Crypto::Network->find must be a coderef returning boolean'
122             ) unless ref $sub eq 'CODE';
123              
124 54         202 return grep { $sub->($networks{$_}) } keys %networks;
  218         507  
125             }
126              
127             sub get
128             {
129 408     408 1 6703 my ($class, $id) = @_;
130              
131 408   66     1866 my $network = $networks{$id // $default_network};
132 408 50       1022 Bitcoin::Crypto::Exception::NetworkConfig->raise(
133             "network $id is not registered"
134             ) unless defined $network;
135              
136 408         7832 return $network;
137             }
138              
139             ### PREDEFINED NETWORKS SECTION
140             # When adding a network, make sure to:
141             # - code in valid constants of the network below
142             # - provide resources that will confirm these constant values (in the merge request)
143             # - add your network to the POD documentation below
144             # - add your network to test file 17-predefined-networks.t
145              
146             ### BITCOIN
147              
148             __PACKAGE__->register(
149             id => 'bitcoin',
150             name => 'Bitcoin Mainnet',
151             p2pkh_byte => "\x00",
152             p2sh_byte => "\x05",
153             wif_byte => "\x80",
154             segwit_hrp => 'bc',
155              
156             extprv_version => 0x0488ade4,
157             extpub_version => 0x0488b21e,
158              
159             extprv_compat_version => 0x049d7878,
160             extpub_compat_version => 0x049d7cb2,
161              
162             extprv_segwit_version => 0x04b2430c,
163             extpub_segwit_version => 0x04b24746,
164              
165             bip44_coin => 0,
166             )->set_default;
167              
168             __PACKAGE__->register(
169             id => 'bitcoin_testnet',
170             name => 'Bitcoin Testnet',
171             p2pkh_byte => "\x6f",
172             p2sh_byte => "\xc4",
173             wif_byte => "\xef",
174             segwit_hrp => 'tb',
175              
176             extprv_version => 0x04358394,
177             extpub_version => 0x043587cf,
178              
179             extprv_compat_version => 0x044a4e28,
180             extpub_compat_version => 0x044a5262,
181              
182             extprv_segwit_version => 0x045f18bc,
183             extpub_segwit_version => 0x045f1cf6,
184              
185             bip44_coin => 1,
186             );
187              
188             ### DOGECOIN
189              
190             __PACKAGE__->register(
191             id => 'dogecoin',
192             name => 'Dogecoin Mainnet',
193             p2pkh_byte => "\x1e",
194             p2sh_byte => "\x16",
195             wif_byte => "\x9e",
196              
197             extprv_version => 0x02fac398,
198             extpub_version => 0x02facafd,
199              
200             bip44_coin => 3,
201             );
202              
203             __PACKAGE__->register(
204             id => 'dogecoin_testnet',
205             name => 'Dogecoin Testnet',
206             p2pkh_byte => "\x71",
207             p2sh_byte => "\xc4",
208             wif_byte => "\xf1",
209              
210             extprv_version => 0x04358394,
211             extpub_version => 0x043587cf,
212              
213             bip44_coin => 1,
214             );
215              
216             1;
217              
218             __END__
219             =head1 NAME
220              
221             Bitcoin::Crypto::Network - Management tool for cryptocurrency networks
222              
223             =head1 SYNOPSIS
224              
225             use Bitcoin::Crypto::Network;
226              
227             # by default network is set to bitcoin
228             # get() without arguments returns default network
229              
230             Bitcoin::Crypto::Network->get->name; # Bitcoin Mainnet
231              
232             # by default there are two networks specified
233             # find() without arguments returns a list of all network ids
234              
235             Bitcoin::Crypto::Network->find; # (mainnet, testnet)
236              
237             # you can get full network configuration with get() using network id
238              
239             Bitcoin::Crypto::Network->get('bitcoin_testnet')->name; # Bitcoin Testnet
240              
241             # search for network and get array of keys in return
242             # there will be multiple results if your search is matched
243             # by multiple networks
244              
245             Bitcoin::Crypto::Network->find(sub { shift->name eq 'Bitcoin Mainnet' }); # (mainnet)
246             Bitcoin::Crypto::Network->find(sub { shift->p2pkh_byte eq "\x6f" }); # (testnet)
247              
248             # if you're working with cryptocurrency other than Bitcoin you need to add a new network
249              
250             # network configuration is important for importing WIF private keys (network
251             # recognition), generating addresses and serializing extended keys.
252             # It may also hold other data specific to a network
253              
254             # register() can be used to create a network
255              
256             my $litecoin = Bitcoin::Crypto::Network->register(
257             id => 'litecoin',
258             name => 'Litecoin Mainnet',
259             p2pkh_byte => "\x30",
260             wif_byte => "\xb0",
261             );
262              
263             # after you've added your network you can set it as default. This means that
264             # all extended keys generated by other means than importing serialized key and
265             # all private keys generated by other means than importing WIF / extended keys
266             # will use that configuration.
267              
268             $litecoin->set_default;
269              
270              
271             =head1 DESCRIPTION
272              
273             This package allows you to manage non-bitcoin cryptocurrencies.
274             Before you start producing keys and addresses for your favorite crypto
275             you have to configure its network first.
276              
277             =head1 PREDEFINED NETWORKS
278              
279             Here is a list of networks that are already defined and can be used without defining them.
280              
281             If you want to see more predefined networks added and you're willing to make
282             some research to find out the correct values for the configuration fields,
283             consider opening a pull request on Github.
284              
285             =head2 Bitcoin Mainnet
286              
287             defined with id: C<bitcoin>
288              
289             =head2 Bitcoin Testnet
290              
291             defined with id: C<bitcoin_testnet>
292              
293             =head2 Dogecoin Mainnet
294              
295             defined with id: C<dogecoin>
296              
297             =head2 Dogecoin Testnet
298              
299             defined with id: C<dogecoin_testnet>
300              
301             =head1 CONFIGURATION
302              
303             Right now networks only require four keys, which are marked with C<(*)>
304              
305             my %config = (
306             id => "(*) identifier for the network",
307             name => "(*) human-readable network name",
308             p2pkh_byte => "(*) p2pkh address prefix byte, eg. 0x00",
309             wif_byte => "(*) WIF private key prefix byte, eg. 0x80",
310             p2sh_byte => "p2sh address prefix byte, eg. 0x05",
311             segwit_hrp => "segwit native address human readable part, eg. 'bc'",
312              
313             extprv_version => "version prefix of serialized extended private keys, eg. 0x0488ade4",
314             extpub_version => "version prefix of serialized extended public keys, eg. 0x0488b21e",
315             extprv_compat_version => "same as extprv_version, but for BIP49",
316             extpub_compat_version => "same as extpub_version, but for BIP49",
317             extprv_segwit_version => "same as extprv_version, but for BIP84",
318             extpub_segwit_version => "same as extpub_version, but for BIP84",
319              
320             bip44_coin => "bip44 coin number, eg. 0",
321             );
322              
323             After you register a network with this hashref your program will be able to import keys for that
324             network but all keys created from other sources will be treated as Bitcoin.
325             You need to set_default to make all new keys use it. If you use many
326             networks it might be better to set a network with key's set_network method:
327              
328             $priv->set_network('network_id');
329              
330             Remember that if you don't specify network field for some feature you won't be able to
331             use it. For example the module will complain if you try to generate segwit address
332             with custom network without segwit_hrp field set.
333              
334             =head1 METHODS
335              
336             =head2 register
337              
338             $network_object = $class->register(%config)
339             $network_object = $object->register()
340              
341             Adds the network instance to a list of known networks.
342              
343             Calls L</new> with keys present in C<%config> hash when called in static context.
344              
345             Returns the network instance.
346              
347             =head2 set_default
348              
349             $network_object = $object->set_default()
350              
351             Sets the network as default one. All newly created private and public keys will be bound to this network.
352              
353             Returns the network instance.
354              
355             =head2 supports_segwit
356              
357             $bool = $object->supports_segwit()
358              
359             Returns a boolean which can be used to determine whether a given network has segwit configured.
360              
361             =head2 new
362              
363             $network_object = $class->new(%config)
364              
365             Creates a new network instance. See L</CONFIGURATION> for a list of possible C<%config> keys.
366              
367             =head2 get
368              
369             $network_object = $class->get($id = undef)
370              
371             Without arguments, returns the default network configuration as the Bitcoin::Crypto::Network instance.
372              
373             With the C<$id> argument (string), returns the instance of a configuration matching the id.
374              
375             Throws an exception if network doesn't exist.
376              
377             =head2 find
378              
379             @network_objects = $class->find($sub = undef)
380              
381             Without arguments, returns a list of all registered network ids.
382              
383             With the C<$sub> argument (coderef), searches for all networks that pass the criteria and returns their ids.
384              
385             Returns list of network instances.
386              
387             The C<$sub> will be passed all the instances of registered networks, one at a time.
388              
389             If must perform required checks and return a boolean value. All the networks that pass this
390             test will be returned. Example:
391              
392             sub {
393             my $instance = shift;
394             return $instance->name eq 'Some name';
395             }
396              
397             =head1 SEE ALSO
398              
399             =over 2
400              
401             =item L<Bitcoin::Crypto::Key::ExtPrivate>
402              
403             =item L<Bitcoin::Crypto::Key::Private>
404              
405             =back
406              
407             =cut
408