File Coverage

blib/lib/Bitcoin/Crypto/Network.pm
Criterion Covered Total %
statement 26 26 100.0
branch n/a
condition n/a
subroutine 9 9 100.0
pod n/a
total 35 35 100.0


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