monacoin-ruby 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 402c242d2512162b5169de6a9a42d60ef0eee0c86f7fe7609438b3f25d8b9e28
4
- data.tar.gz: 977043c3719fe54dd9338cca69ebfbb2e9c3d49394852a2cb86e3458b6f7a212
3
+ metadata.gz: c5f657b65bdb51796fcaa25c6edde7918abf290860d50b2167bf861a99ecc7a7
4
+ data.tar.gz: b604b71b2b2fbb87b1230d749e6dcc6e4fc0c02e2421e5fba80d6de630a8b5a2
5
5
  SHA512:
6
- metadata.gz: 2b40e18d59c045a8e775eccf6d2f54beeb355db7dda2b45d1809d24d5e6c03b3c7232567df6d090fc6846d92b604b2b73b038a9d0f37115c08fbe65d750551b0
7
- data.tar.gz: 96121a28ffc81b450e64cd6c090b5b95bbad96ea7456d3eff54a6460189fc62ee9afabdd7c7e8c4071166f29981e8e7ac173afdcd9868b4530ad9175132a81e7
6
+ metadata.gz: 264b31023f8dc2daa6a30eb488b4569ce24580b76410a85d32cc0807f955619c24f2882678cad1b73edb602d7b25f545bf445e2018bd6ceb3829378e2dc769c3
7
+ data.tar.gz: aec29ed5a9a7d5ce44ce0bf38293352af733a031c87e053bc2f710707ab79942f5d9efe8b86a90bc2ac91ecd698e599c7bf69f3838f2b8a9a7a84289aa9e5761
data/lib/bitcoin.rb ADDED
@@ -0,0 +1,933 @@
1
+ # encoding: ascii-8bit
2
+ # Bitcoin Utils and Network Protocol in Ruby.
3
+
4
+ require 'digest/sha2'
5
+ require 'digest/rmd160'
6
+ require 'openssl'
7
+ require 'securerandom'
8
+
9
+ module Bitcoin
10
+
11
+ autoload :Connection, 'bitcoin/connection'
12
+ autoload :Protocol, 'bitcoin/protocol'
13
+ autoload :P, 'bitcoin/protocol'
14
+ autoload :Script, 'bitcoin/script'
15
+ autoload :VERSION, 'bitcoin/version'
16
+ autoload :Logger, 'bitcoin/logger'
17
+ autoload :Key, 'bitcoin/key'
18
+ autoload :ExtKey, 'bitcoin/ext_key'
19
+ autoload :ExtPubkey, 'bitcoin/ext_key'
20
+ autoload :Builder, 'bitcoin/builder'
21
+ autoload :BloomFilter,'bitcoin/bloom_filter'
22
+
23
+ autoload :Dogecoin, 'bitcoin/dogecoin'
24
+ autoload :Litecoin, 'bitcoin/litecoin'
25
+
26
+ autoload :ContractHash, 'bitcoin/contracthash'
27
+
28
+ module Trezor
29
+ autoload :Mnemonic, 'bitcoin/trezor/mnemonic'
30
+ end
31
+
32
+
33
+ module Util
34
+
35
+ def address_version; Bitcoin.network[:address_version]; end
36
+ def p2sh_version; Bitcoin.network[:p2sh_version]; end
37
+
38
+ # hash160 is a 20 bytes (160bits) rmd610-sha256 hexdigest.
39
+ def hash160(hex)
40
+ bytes = [hex].pack("H*")
41
+ Digest::RMD160.hexdigest Digest::SHA256.digest(bytes)
42
+ end
43
+
44
+ # checksum is a 4 bytes sha256-sha256 hexdigest.
45
+ def checksum(hex)
46
+ b = [hex].pack("H*") # unpack hex
47
+ Digest::SHA256.hexdigest( Digest::SHA256.digest(b) )[0...8]
48
+ end
49
+
50
+ # verify base58 checksum for given +base58+ data.
51
+ def base58_checksum?(base58)
52
+ hex = decode_base58(base58) rescue nil
53
+ return false unless hex
54
+ checksum( hex[0...42] ) == hex[-8..-1]
55
+ end
56
+ alias :address_checksum? :base58_checksum?
57
+
58
+ # check if given +address+ is valid.
59
+ # this means having a correct version byte, length and checksum.
60
+ def valid_address?(address)
61
+ hex = decode_base58(address) rescue nil
62
+ return false unless hex && hex.bytesize == 50
63
+ return false unless [address_version, p2sh_version].include?(hex[0...2])
64
+ address_checksum?(address)
65
+ end
66
+
67
+ # check if given +pubkey+ is valid.
68
+ def valid_pubkey?(pubkey)
69
+ ::OpenSSL::PKey::EC::Point.from_hex(bitcoin_elliptic_curve.group, pubkey)
70
+ true
71
+ rescue OpenSSL::PKey::EC::Point::Error
72
+ false
73
+ end
74
+
75
+ # get hash160 for given +address+. returns nil if address is invalid.
76
+ def hash160_from_address(address)
77
+ return nil unless valid_address?(address)
78
+ decode_base58(address)[2...42]
79
+ end
80
+
81
+ # get type of given +address+.
82
+ def address_type(address)
83
+ return nil unless valid_address?(address)
84
+ case decode_base58(address)[0...2]
85
+ when address_version; :hash160
86
+ when p2sh_version; :p2sh
87
+ end
88
+ end
89
+
90
+ def sha256(hex)
91
+ Digest::SHA256.hexdigest([hex].pack("H*"))
92
+ end
93
+
94
+ def hash160_to_address(hex)
95
+ encode_address hex, address_version
96
+ end
97
+
98
+ def hash160_to_p2sh_address(hex)
99
+ encode_address hex, p2sh_version
100
+ end
101
+
102
+ def encode_address(hex, version)
103
+ hex = version + hex
104
+ encode_base58(hex + checksum(hex))
105
+ end
106
+
107
+ def pubkey_to_address(pubkey)
108
+ hash160_to_address( hash160(pubkey) )
109
+ end
110
+
111
+ def pubkeys_to_p2sh_multisig_address(m, *pubkeys)
112
+ redeem_script = Bitcoin::Script.to_p2sh_multisig_script(m, *pubkeys).last
113
+ return Bitcoin.hash160_to_p2sh_address(Bitcoin.hash160(redeem_script.hth)), redeem_script
114
+ end
115
+
116
+ def int_to_base58(int_val, leading_zero_bytes=0)
117
+ alpha = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
118
+ base58_val, base = '', alpha.size
119
+ while int_val > 0
120
+ int_val, remainder = int_val.divmod(base)
121
+ base58_val = alpha[remainder] + base58_val
122
+ end
123
+ base58_val
124
+ end
125
+
126
+ def base58_to_int(base58_val)
127
+ alpha = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
128
+ int_val, base = 0, alpha.size
129
+ base58_val.reverse.each_char.with_index do |char,index|
130
+ raise ArgumentError, 'Value not a valid Base58 String.' unless char_index = alpha.index(char)
131
+ int_val += char_index*(base**index)
132
+ end
133
+ int_val
134
+ end
135
+
136
+ def encode_base58(hex)
137
+ leading_zero_bytes = (hex.match(/^([0]+)/) ? $1 : '').size / 2
138
+ ("1"*leading_zero_bytes) + int_to_base58( hex.to_i(16) )
139
+ end
140
+
141
+ def decode_base58(base58_val)
142
+ s = base58_to_int(base58_val).to_s(16); s = (s.bytesize.odd? ? '0'+s : s)
143
+ s = '' if s == '00'
144
+ leading_zero_bytes = (base58_val.match(/^([1]+)/) ? $1 : '').size
145
+ s = ("00"*leading_zero_bytes) + s if leading_zero_bytes > 0
146
+ s
147
+ end
148
+ alias_method :base58_to_hex, :decode_base58
149
+
150
+ # target compact bits (int) to bignum hex
151
+ def decode_compact_bits(bits)
152
+ if Bitcoin.network_project == :dogecoin
153
+ bytes = Array.new(size=((bits >> 24) & 255), 0)
154
+ bytes[0] = (bits >> 16) & 0x7f if size >= 1
155
+ bytes[1] = (bits >> 8) & 255 if size >= 2
156
+ bytes[2] = (bits ) & 255 if size >= 3
157
+ target = bytes.pack("C*").unpack("H*")[0].rjust(64, '0')
158
+ # Bit number 24 represents the sign
159
+ if (bits & 0x00800000) != 0
160
+ "-" + target
161
+ else
162
+ target
163
+ end
164
+ else
165
+ bytes = Array.new(size=((bits >> 24) & 255), 0)
166
+ bytes[0] = (bits >> 16) & 255 if size >= 1
167
+ bytes[1] = (bits >> 8) & 255 if size >= 2
168
+ bytes[2] = (bits ) & 255 if size >= 3
169
+ bytes.pack("C*").unpack("H*")[0].rjust(64, '0')
170
+ end
171
+ end
172
+
173
+ # target bignum hex to compact bits (int)
174
+ def encode_compact_bits(target)
175
+ bytes = OpenSSL::BN.new(target, 16).to_mpi
176
+ size = bytes.size - 4
177
+ nbits = size << 24
178
+ nbits |= (bytes[4] << 16) if size >= 1
179
+ nbits |= (bytes[5] << 8) if size >= 2
180
+ nbits |= (bytes[6] ) if size >= 3
181
+ nbits
182
+ end
183
+
184
+ def decode_target(target_bits)
185
+ case target_bits
186
+ when Fixnum
187
+ [ decode_compact_bits(target_bits).to_i(16), target_bits ]
188
+ when String
189
+ [ target_bits.to_i(16), encode_compact_bits(target_bits) ]
190
+ end
191
+ end
192
+
193
+ def bitcoin_elliptic_curve
194
+ ::OpenSSL::PKey::EC.new("secp256k1")
195
+ end
196
+
197
+ def generate_key
198
+ key = bitcoin_elliptic_curve.generate_key
199
+ inspect_key( key )
200
+ end
201
+
202
+ def inspect_key(key)
203
+ [ key.private_key_hex, key.public_key_hex ]
204
+ end
205
+
206
+ def generate_address
207
+ prvkey, pubkey = generate_key
208
+ [ pubkey_to_address(pubkey), prvkey, pubkey, hash160(pubkey) ]
209
+ end
210
+
211
+ def bitcoin_hash(hex)
212
+ Digest::SHA256.digest(
213
+ Digest::SHA256.digest( [hex].pack("H*").reverse )
214
+ ).reverse.bth
215
+ end
216
+
217
+ def bitcoin_byte_hash(bytes)
218
+ Digest::SHA256.digest(Digest::SHA256.digest(bytes))
219
+ end
220
+
221
+ def bitcoin_mrkl(a, b); bitcoin_hash(b + a); end
222
+
223
+ def block_hash(prev_block, mrkl_root, time, bits, nonce, ver)
224
+ h = "%08x%08x%08x%064s%064s%08x" %
225
+ [nonce, bits, time, mrkl_root, prev_block, ver]
226
+ bitcoin_hash(h)
227
+ end
228
+
229
+ def litecoin_hash(hex)
230
+ bytes = [hex].pack("H*").reverse
231
+ begin
232
+ require "scrypt" unless defined?(::SCrypt)
233
+ hash = SCrypt::Engine.__sc_crypt(bytes, bytes, 1024, 1, 1, 32)
234
+ rescue LoadError
235
+ hash = Litecoin::Scrypt.scrypt_1024_1_1_256_sp(bytes)
236
+ end
237
+ hash.reverse.unpack("H*")[0]
238
+ end
239
+
240
+ def block_scrypt_hash(prev_block, mrkl_root, time, bits, nonce, ver)
241
+ h = "%08x%08x%08x%064s%064s%08x" %
242
+ [nonce, bits, time, mrkl_root, prev_block, ver]
243
+ litecoin_hash(h)
244
+ end
245
+
246
+ # get merkle tree for given +tx+ list.
247
+ def hash_mrkl_tree(tx)
248
+ return [nil] if tx != tx.uniq
249
+ chunks = [ tx.dup ]
250
+ while chunks.last.size >= 2
251
+ chunks << chunks.last.each_slice(2).map {|a, b| bitcoin_mrkl( a, b || a ) }
252
+ end
253
+ chunks.flatten
254
+ end
255
+
256
+ # get merkle branch connecting given +target+ to the merkle root of +tx+ list
257
+ def hash_mrkl_branch(tx, target)
258
+ return [ nil ] if tx != tx.uniq
259
+ branch, chunks = [], [ tx.dup ]
260
+ while chunks.last.size >= 2
261
+ chunks << chunks.last.each_slice(2).map {|a, b|
262
+ hash = bitcoin_mrkl( a, b || a )
263
+ next hash unless [a, b].include?(target)
264
+ branch << (a == target ? (b || a) : a)
265
+ target = hash
266
+ }
267
+ end
268
+ branch
269
+ end
270
+
271
+ # get merkle root from +branch+ and +target+.
272
+ def mrkl_branch_root(branch, target, idx)
273
+ branch.each do |hash|
274
+ a, b = *( idx & 1 == 0 ? [target, hash] : [hash, target] )
275
+ idx >>= 1;
276
+ target = bitcoin_mrkl( a, b )
277
+ end
278
+ target
279
+ end
280
+
281
+ def sign_data(key, data)
282
+ sig = nil
283
+ loop {
284
+ sig = key.dsa_sign_asn1(data)
285
+ sig = if Script.is_low_der_signature?(sig)
286
+ sig
287
+ else
288
+ Bitcoin::OpenSSL_EC.signature_to_low_s(sig)
289
+ end
290
+
291
+ buf = sig + [Script::SIGHASH_TYPE[:all]].pack("C") # is_der_signature expects sig + sighash_type format
292
+ if Script.is_der_signature?(buf)
293
+ break
294
+ else
295
+ p ["Bitcoin#sign_data: invalid der signature generated, trying again.", data.unpack("H*")[0], sig.unpack("H*")[0]]
296
+ end
297
+ }
298
+ return sig
299
+ end
300
+
301
+ def verify_signature(hash, signature, public_key)
302
+ key = bitcoin_elliptic_curve
303
+ key.public_key = ::OpenSSL::PKey::EC::Point.from_hex(key.group, public_key)
304
+ signature = Bitcoin::OpenSSL_EC.repack_der_signature(signature)
305
+ if signature
306
+ key.dsa_verify_asn1(hash, signature)
307
+ else
308
+ false
309
+ end
310
+ rescue OpenSSL::PKey::ECError, OpenSSL::PKey::EC::Point::Error, OpenSSL::BNError
311
+ false
312
+ end
313
+
314
+ def open_key(private_key, public_key=nil)
315
+ key = bitcoin_elliptic_curve
316
+ key.private_key = ::OpenSSL::BN.from_hex(private_key)
317
+ public_key = regenerate_public_key(private_key) unless public_key
318
+ key.public_key = ::OpenSSL::PKey::EC::Point.from_hex(key.group, public_key)
319
+ key
320
+ end
321
+
322
+ def regenerate_public_key(private_key)
323
+ OpenSSL_EC.regenerate_key(private_key)[1]
324
+ end
325
+
326
+ def bitcoin_signed_message_hash(message)
327
+ message = message.dup.force_encoding('binary')
328
+
329
+ magic = Bitcoin.network[:message_magic]
330
+ buf = Protocol.pack_var_int(magic.bytesize) + magic
331
+ buf << Protocol.pack_var_int(message.bytesize) + message
332
+
333
+ Digest::SHA256.digest(Digest::SHA256.digest(buf))
334
+ end
335
+
336
+ def sign_message(private_key_hex, public_key_hex, message)
337
+ hash = bitcoin_signed_message_hash(message)
338
+ signature = OpenSSL_EC.sign_compact(hash, private_key_hex, public_key_hex)
339
+ { 'address' => pubkey_to_address(public_key_hex), 'message' => message, 'signature' => [ signature ].pack("m0") }
340
+ end
341
+
342
+ def verify_message(address, signature, message)
343
+ signature = signature.unpack("m0")[0] rescue nil # decode base64
344
+ return false unless valid_address?(address)
345
+ return false unless signature
346
+ return false unless signature.bytesize == 65
347
+ hash = bitcoin_signed_message_hash(message)
348
+ pubkey = OpenSSL_EC.recover_compact(hash, signature)
349
+ pubkey_to_address(pubkey) == address if pubkey
350
+ end
351
+
352
+ # block count when the next retarget will take place.
353
+ def block_next_retarget(block_height)
354
+ (block_height + (RETARGET_INTERVAL-block_height.divmod(RETARGET_INTERVAL).last)) - 1
355
+ end
356
+
357
+ # current difficulty as a multiple of the minimum difficulty (highest target).
358
+ def block_difficulty(target_nbits)
359
+ # max_target = 0x00000000ffff0000000000000000000000000000000000000000000000000000
360
+ # current_target = Bitcoin.decode_compact_bits(target_nbits).to_i(16)
361
+ # "%.7f" % (max_target / current_target.to_f)
362
+ bits, max_body, scaland = target_nbits, Math.log(0x00ffff), Math.log(256)
363
+ "%.7f" % Math.exp(max_body - Math.log(bits&0x00ffffff) + scaland * (0x1d - ((bits&0xff000000)>>24)))
364
+ end
365
+
366
+ # Calculate new difficulty target. Note this takes in details of the preceeding
367
+ # block, not the current one.
368
+ #
369
+ # prev_height is the height of the block before the retarget occurs
370
+ # prev_block_time "time" field from the block before the retarget occurs
371
+ # prev_block_bits "bits" field from the block before the retarget occurs (target as a compact value)
372
+ # last_retarget_time is the "time" field from the block when a retarget last occurred
373
+ def block_new_target(prev_height, prev_block_time, prev_block_bits, last_retarget_time)
374
+ # target interval - what is the ideal interval between the blocks
375
+ retarget_time = Bitcoin.network[:retarget_time]
376
+
377
+ actual_time = prev_block_time - last_retarget_time
378
+
379
+ min = retarget_time / 4
380
+ max = retarget_time * 4
381
+
382
+ actual_time = min if actual_time < min
383
+ actual_time = max if actual_time > max
384
+
385
+ # It could be a bit confusing: we are adjusting difficulty of the previous block, while logically
386
+ # we should use difficulty of the previous retarget block
387
+
388
+ prev_target = decode_compact_bits(prev_block_bits).to_i(16)
389
+
390
+ new_target = prev_target * actual_time / retarget_time
391
+ if new_target < Bitcoin.decode_compact_bits(Bitcoin.network[:proof_of_work_limit]).to_i(16)
392
+ encode_compact_bits(new_target.to_s(16))
393
+ else
394
+ Bitcoin.network[:proof_of_work_limit]
395
+ end
396
+ end
397
+
398
+ # average number of hashes required to win a block with the current target. (nbits)
399
+ def block_hashes_to_win(target_nbits)
400
+ current_target = decode_compact_bits(target_nbits).to_i(16)
401
+ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff / current_target
402
+ end
403
+
404
+ # probability of a single hash solving a block with the current difficulty.
405
+ def block_probability(target_nbits)
406
+ current_target = decode_compact_bits(target_nbits).to_i(16)
407
+ "%.55f" % (current_target.to_f / 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
408
+ end
409
+
410
+ # average time to find a block in seconds with the current target. (nbits)
411
+ def block_average_hashing_time(target_nbits, hashes_per_second)
412
+ block_hashes_to_win(target_nbits) / hashes_per_second
413
+ end
414
+
415
+ # average mining time (in days) using Mh/s to get btc
416
+ def block_average_mining_time(block_nbits, block_height, mega_hashes_per_second, target_btc=1.0)
417
+ seconds = block_average_hashing_time(block_nbits, mega_hashes_per_second * 1_000_000)
418
+ reward = block_creation_reward(block_height) / COIN # satoshis to btc
419
+ (days = seconds / 60 / 60 / 24) * (target_btc / reward)
420
+ end
421
+
422
+ # shows the total number of Bitcoins in circulation, reward era and reward in that era.
423
+ def blockchain_total_btc(height)
424
+ reward, interval = Bitcoin.network[:reward_base], Bitcoin.network[:reward_halving]
425
+ total_btc = reward
426
+ reward_era, remainder = (height).divmod(interval)
427
+ reward_era.times{
428
+ total_btc += interval * reward
429
+ reward = reward / 2
430
+ }
431
+ total_btc += remainder * reward
432
+ [total_btc, reward_era+1, reward, height]
433
+ end
434
+
435
+ def block_creation_reward(block_height)
436
+ Bitcoin.network[:reward_base] / (2 ** (block_height / Bitcoin.network[:reward_halving].to_f).floor)
437
+ end
438
+ end
439
+
440
+ extend Util
441
+
442
+
443
+ module BinaryExtensions
444
+ # bin-to-hex
445
+ def bth; unpack("H*")[0]; end
446
+ # hex-to-bin
447
+ def htb; [self].pack("H*"); end
448
+
449
+ def htb_reverse; htb.reverse; end
450
+ def hth; unpack("H*")[0]; end
451
+ def reverse_hth; reverse.hth; end
452
+ end
453
+
454
+ class ::String
455
+ include Bitcoin::BinaryExtensions
456
+ end
457
+
458
+
459
+ module ::OpenSSL
460
+ class BN
461
+ def self.from_hex(hex); new(hex, 16); end
462
+ def to_hex; to_i.to_s(16); end
463
+ def to_mpi; to_s(0).unpack("C*"); end
464
+ end
465
+ class PKey::EC
466
+ def private_key_hex; private_key.to_hex.rjust(64, '0'); end
467
+ def public_key_hex; public_key.to_hex.rjust(130, '0'); end
468
+ def pubkey_compressed?; public_key.group.point_conversion_form == :compressed; end
469
+ end
470
+ class PKey::EC::Point
471
+ def self.from_hex(group, hex)
472
+ new(group, BN.from_hex(hex))
473
+ end
474
+ def to_hex; to_bn.to_hex; end
475
+ def self.bn2mpi(hex) BN.from_hex(hex).to_mpi; end
476
+ def ec_add(point); self.class.new(group, OpenSSL::BN.from_hex(OpenSSL_EC.ec_add(self, point))); end
477
+ end
478
+ end
479
+
480
+ autoload :OpenSSL_EC, "bitcoin/ffi/openssl"
481
+
482
+ autoload :Secp256k1, "bitcoin/ffi/secp256k1"
483
+ autoload :BitcoinConsensus, "bitcoin/ffi/bitcoinconsensus"
484
+
485
+ @network = :bitcoin
486
+
487
+ def self.network
488
+ # Store the copy of network options so we can modify them in tests without breaking the defaults
489
+ @network_options ||= NETWORKS[@network].dup
490
+ end
491
+
492
+ def self.network_name
493
+ @network
494
+ end
495
+
496
+ def self.network_project
497
+ @network_project
498
+ end
499
+
500
+ def self.network=(name)
501
+ raise "Network descriptor '#{name}' not found." unless NETWORKS[name.to_sym]
502
+ @network_options = nil # clear cached parameters
503
+ @network = name.to_sym
504
+ @network_project = network[:project] rescue nil
505
+ Dogecoin.load if dogecoin? || dogecoin_testnet?
506
+ Namecoin.load if namecoin? && defined?(Namecoin)
507
+ @network
508
+ end
509
+
510
+ [:bitcoin, :namecoin, :litecoin, :dogecoin, :dogecoin_testnet].each do |n|
511
+ instance_eval "def #{n}?; network_project == :#{n}; end"
512
+ end
513
+
514
+
515
+ # maximum size of a block (in bytes)
516
+ MAX_BLOCK_SIZE = 1_000_000
517
+
518
+ # soft limit for new blocks
519
+ MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2
520
+
521
+ # maximum number of signature operations in a block
522
+ MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE / 50
523
+
524
+ # maximum number of orphan transactions to be kept in memory
525
+ MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100
526
+
527
+ # Threshold for lock_time: below this value it is interpreted as block number, otherwise as UNIX timestamp.
528
+ LOCKTIME_THRESHOLD = 500000000 # Tue Nov 5 00:53:20 1985 UTC
529
+
530
+ # maximum integer value
531
+ UINT32_MAX = 0xffffffff
532
+ INT_MAX = 0xffffffff # deprecated name, left here for compatibility with existing users.
533
+
534
+ # number of confirmations required before coinbase tx can be spent
535
+ COINBASE_MATURITY = 100
536
+
537
+ # interval (in blocks) for difficulty retarget
538
+ RETARGET_INTERVAL = 2016
539
+ RETARGET = 2016 # deprecated constant
540
+
541
+
542
+ # interval (in blocks) for mining reward reduction
543
+ REWARD_DROP = 210_000
544
+
545
+ CENT = 1_000_000
546
+ COIN = 100_000_000
547
+
548
+ MIN_FEE_MODE = [ :block, :relay, :send ]
549
+
550
+ NETWORKS = {
551
+ bitcoin: {
552
+ project: :bitcoin,
553
+ magic_head: "\xF9\xBE\xB4\xD9",
554
+ message_magic: "Bitcoin Signed Message:\n",
555
+ address_version: "00",
556
+ p2sh_version: "05",
557
+ privkey_version: "80",
558
+ extended_privkey_version: "0488ade4",
559
+ extended_pubkey_version: "0488b21e",
560
+ default_port: 8333,
561
+ protocol_version: 70001,
562
+ coinbase_maturity: 100,
563
+ reward_base: 50 * COIN,
564
+ reward_halving: 210_000,
565
+ retarget_interval: 2016,
566
+ retarget_time: 1209600, # 2 weeks
567
+ target_spacing: 600, # block interval
568
+ max_money: 21_000_000 * COIN,
569
+ min_tx_fee: 10_000,
570
+ min_relay_tx_fee: 10_000,
571
+ free_tx_bytes: 1_000,
572
+ dust: CENT,
573
+ per_dust_fee: false,
574
+ bip34_height: 227931,
575
+ dns_seeds: [
576
+ "seed.bitcoin.sipa.be",
577
+ "dnsseed.bluematt.me",
578
+ "dnsseed.bitcoin.dashjr.org",
579
+ "bitseed.xf2.org",
580
+ "dnsseed.webbtc.com",
581
+ ],
582
+ genesis_hash: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
583
+ proof_of_work_limit: 0x1d00ffff,
584
+ alert_pubkeys: ["04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284"],
585
+ known_nodes: [
586
+ 'relay.eligius.st',
587
+ 'mining.bitcoin.cz',
588
+ 'blockchain.info',
589
+ 'blockexplorer.com',
590
+ 'webbtc.com',
591
+ ],
592
+ checkpoints: {
593
+ 11111 => "0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d",
594
+ 33333 => "000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6",
595
+ 74000 => "0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20",
596
+ 105000 => "00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97",
597
+ 134444 => "00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe",
598
+ 168000 => "000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763",
599
+ 193000 => "000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317",
600
+ 210000 => "000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e",
601
+ 216116 => "00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e",
602
+ 225430 => "00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932",
603
+ 290000 => "0000000000000000fa0b2badd05db0178623ebf8dd081fe7eb874c26e27d0b3b",
604
+ 300000 => "000000000000000082ccf8f1557c5d40b21edabb18d2d691cfbf87118bac7254",
605
+ 305000 => "0000000000000000142bb90561e1a907d500bf534a6727a63a92af5b6abc6160",
606
+ }
607
+ }
608
+ }
609
+
610
+ NETWORKS[:testnet] = NETWORKS[:bitcoin].merge({
611
+ magic_head: "\xFA\xBF\xB5\xDA",
612
+ address_version: "6f",
613
+ p2sh_version: "c4",
614
+ privkey_version: "ef",
615
+ extended_privkey_version: "04358394",
616
+ extended_pubkey_version: "043587cf",
617
+ default_port: 18333,
618
+ bip34_height: 21111,
619
+ dns_seeds: [ ],
620
+ genesis_hash: "00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008",
621
+ proof_of_work_limit: 0x1d07fff8,
622
+ alert_pubkeys: ["04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a"],
623
+ known_nodes: [],
624
+ checkpoints: {},
625
+ })
626
+
627
+ NETWORKS[:regtest] = NETWORKS[:testnet].merge({
628
+ default_port: 18444,
629
+ genesis_hash: "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206",
630
+ proof_of_work_limit: 0x207fffff,
631
+ bip34_height: 0,
632
+ })
633
+
634
+ NETWORKS[:testnet3] = NETWORKS[:testnet].merge({
635
+ magic_head: "\x0B\x11\x09\x07",
636
+ no_difficulty: true, # no good. add right testnet3 difficulty calculation instead
637
+ genesis_hash: "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943",
638
+ proof_of_work_limit: 0x1d00ffff,
639
+ dns_seeds: [
640
+ "testnet-seed.alexykot.me",
641
+ "testnet-seed.bitcoin.schildbach.de",
642
+ "testnet-seed.bitcoin.petertodd.org",
643
+ "testnet-seed.bluematt.me",
644
+ "dnsseed.test.webbtc.com",
645
+ ],
646
+ known_nodes: ["test.webbtc.com"],
647
+ checkpoints: {
648
+ # 542 contains invalid transaction
649
+ 542 => "0000000083c1f82cf72c6724f7a317325806384b06408bce7a4327f418dfd5ad",
650
+ 71018 => "000000000010dd93dc55541116b2744eb8f4c3b706df6e8512d231a03fb9e435",
651
+ 200000 => "0000000000287bffd321963ef05feab753ebe274e1d78b2fd4e2bfe9ad3aa6f2",
652
+ 250000 => "0000000005910c146e4e8d71e8aa6617393738a9794b43cf113076dbaf08460b",
653
+ }
654
+ })
655
+
656
+ NETWORKS[:litecoin] = NETWORKS[:bitcoin].merge({
657
+ project: :litecoin,
658
+ magic_head: "\xfb\xc0\xb6\xdb",
659
+ message_magic: "Litecoin Signed Message:\n",
660
+ address_version: "30",
661
+ p2sh_version: "32",
662
+ privkey_version: "b0",
663
+ extended_privkey_version: "019d9cfe",
664
+ extended_pubkey_version: "019da462",
665
+ default_port: 9333,
666
+ protocol_version: 70002,
667
+ max_money: 84_000_000 * COIN,
668
+ min_tx_fee: 100_000, # 0.001 LTC
669
+ min_relay_tx_fee: 100_000, # 0.001 LTC
670
+ free_tx_bytes: 5_000,
671
+ dust: CENT / 10,
672
+ per_dust_fee: false,
673
+ reward_halving: 840_000,
674
+ retarget_time: 302400, # 3.5 days
675
+ dns_seeds: [
676
+ "dnsseed.litecointools.com",
677
+ "dnsseed.litecoinpool.org",
678
+ "seed-a.litecoin.loshan.co.uk",
679
+ "dnsseed.thrasher.io",
680
+ "dnsseed.koin-project.com",
681
+ ],
682
+ genesis_hash: "12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2",
683
+ proof_of_work_limit: 0x1e0fffff,
684
+ alert_pubkeys: ["040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9"],
685
+ known_nodes: [],
686
+ checkpoints: {
687
+ 1 => "80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f",
688
+ 2 => "13957807cdd1d02f993909fa59510e318763f99a506c4c426e3b254af09f40d7",
689
+ 1500 => "841a2965955dd288cfa707a755d05a54e45f8bd476835ec9af4402a2b59a2967",
690
+ 4032 => "9ce90e427198fc0ef05e5905ce3503725b80e26afd35a987965fd7e3d9cf0846",
691
+ 8064 => "eb984353fc5190f210651f150c40b8a4bab9eeeff0b729fcb3987da694430d70",
692
+ 16128 => "602edf1859b7f9a6af809f1d9b0e6cb66fdc1d4d9dcd7a4bec03e12a1ccd153d",
693
+ 23420 => "d80fdf9ca81afd0bd2b2a90ac3a9fe547da58f2530ec874e978fce0b5101b507",
694
+ 50000 => "69dc37eb029b68f075a5012dcc0419c127672adb4f3a32882b2b3e71d07a20a6",
695
+ 80000 => "4fcb7c02f676a300503f49c764a89955a8f920b46a8cbecb4867182ecdb2e90a",
696
+ 120000 => "bd9d26924f05f6daa7f0155f32828ec89e8e29cee9e7121b026a7a3552ac6131",
697
+ 161500 => "dbe89880474f4bb4f75c227c77ba1cdc024991123b28b8418dbbf7798471ff43",
698
+ 179620 => "2ad9c65c990ac00426d18e446e0fd7be2ffa69e9a7dcb28358a50b2b78b9f709",
699
+ 240000 => "7140d1c4b4c2157ca217ee7636f24c9c73db39c4590c4e6eab2e3ea1555088aa",
700
+ 383640 => "2b6809f094a9215bafc65eb3f110a35127a34be94b7d0590a096c3f126c6f364",
701
+ 409004 => "487518d663d9f1fa08611d9395ad74d982b667fbdc0e77e9cf39b4f1355908a3",
702
+ 456000 => "bf34f71cc6366cd487930d06be22f897e34ca6a40501ac7d401be32456372004",
703
+ 541794 => "1cbccbe6920e7c258bbce1f26211084efb19764aa3224bec3f4320d77d6a2fd2",
704
+ },
705
+ auxpow_chain_id: 1,
706
+ })
707
+
708
+ NETWORKS[:litecoin_testnet] = NETWORKS[:litecoin].merge({
709
+ magic_head: "\xfd\xd2\xc8\xf1",
710
+ address_version: "6f",
711
+ p2sh_version: "3a",
712
+ privkey_version: "ef",
713
+ extended_privkey_version: "0436ef7d",
714
+ extended_pubkey_version: "0436f6e1",
715
+ default_port: 19335,
716
+ dns_seeds: [
717
+ "testnet-seed.ltc.xurious.com",
718
+ "seed-b.litecoin.loshan.co.uk",
719
+ "dnsseed-testnet.thrasher.io",
720
+ ],
721
+ genesis_hash: "4966625a4b2851d9fdee139e56211a0d88575f59ed816ff5e6a63deb4e3e29a0",
722
+ alert_pubkeys: ["04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a"],
723
+ known_nodes: [],
724
+ checkpoints: {
725
+ 546 => "bf434a4c665307f52a041ee40faa7bf56284c5f3b5d11bf6182aba537961f86c",
726
+ }
727
+ })
728
+
729
+ NETWORKS[:dogecoin] = NETWORKS[:litecoin].merge({
730
+ project: :dogecoin,
731
+ magic_head: "\xc0\xc0\xc0\xc0",
732
+ message_magic: "Dogecoin Signed Message:\n",
733
+ address_version: "1e",
734
+ p2sh_version: "16",
735
+ privkey_version: "9e",
736
+ extended_privkey_version: "02fac398",
737
+ extended_pubkey_version: "02facafd",
738
+ default_port: 22556,
739
+ protocol_version: 70003,
740
+ max_money: 100_000_000_000 * COIN,
741
+ min_tx_fee: COIN,
742
+ min_relay_tx_fee: COIN,
743
+ free_tx_bytes: 26_000,
744
+ dust: COIN,
745
+ per_dust_fee: true,
746
+ coinbase_maturity: 30,
747
+ coinbase_maturity_new: 240,
748
+ reward_base: 500_000 * COIN,
749
+ reward_halving: 100_000,
750
+ retarget_interval: 240,
751
+ retarget_time: 14400, # 4 hours
752
+ retarget_time_new: 60, # 1 minute
753
+ target_spacing: 60, # block interval
754
+ dns_seeds: [
755
+ "seed.dogechain.info",
756
+ "seed.dogecoin.com",
757
+ ],
758
+ genesis_hash: "1a91e3dace36e2be3bf030a65679fe821aa1d6ef92e7c9902eb318182c355691",
759
+ proof_of_work_limit: 0x1e0fffff,
760
+ alert_pubkeys: [],
761
+ known_nodes: [
762
+ "daemons.chain.so",
763
+ "bootstrap.chain.so",
764
+ ],
765
+ checkpoints: {
766
+ 0 => "1a91e3dace36e2be3bf030a65679fe821aa1d6ef92e7c9902eb318182c355691",
767
+ 42279 => "8444c3ef39a46222e87584ef956ad2c9ef401578bd8b51e8e4b9a86ec3134d3a",
768
+ 42400 => "557bb7c17ed9e6d4a6f9361cfddf7c1fc0bdc394af7019167442b41f507252b4",
769
+ 104679 => "35eb87ae90d44b98898fec8c39577b76cb1eb08e1261cfc10706c8ce9a1d01cf",
770
+ 128370 => "3f9265c94cab7dc3bd6a2ad2fb26c8845cb41cff437e0a75ae006997b4974be6",
771
+ 145000 => "cc47cae70d7c5c92828d3214a266331dde59087d4a39071fa76ddfff9b7bde72",
772
+ 165393 => "7154efb4009e18c1c6a6a79fc6015f48502bcd0a1edd9c20e44cd7cbbe2eeef1",
773
+ 186774 => "3c712c49b34a5f34d4b963750d6ba02b73e8a938d2ee415dcda141d89f5cb23a",
774
+ 199992 => "3408ff829b7104eebaf61fd2ba2203ef2a43af38b95b353e992ef48f00ebb190",
775
+ 225000 => "be148d9c5eab4a33392a6367198796784479720d06bfdd07bd547fe934eea15a",
776
+ 250000 => "0e4bcfe8d970979f7e30e2809ab51908d435677998cf759169407824d4f36460",
777
+ 270639 => "c587a36dd4f60725b9dd01d99694799bef111fc584d659f6756ab06d2a90d911",
778
+ 299742 => "1cc89c0c8a58046bf0222fe131c099852bd9af25a80e07922918ef5fb39d6742",
779
+ 323141 => "60c9f919f9b271add6ef5671e9538bad296d79f7fdc6487ba702bf2ba131d31d",
780
+ 339202 => "8c29048df5ae9df38a67ea9470fdd404d281a3a5c6f33080cd5bf14aa496ab03"
781
+ },
782
+ auxpow_chain_id: 0x0062,
783
+ # Doge-specific hard-fork cutoffs
784
+ difficulty_change_block: 145000,
785
+ maturity_change_block: 145000,
786
+ auxpow_start_block: 371337
787
+ })
788
+
789
+ NETWORKS[:dogecoin_testnet] = NETWORKS[:dogecoin].merge({
790
+ project: :dogecoin,
791
+ magic_head: "\xfc\xc1\xb7\xdc",
792
+ address_version: "71",
793
+ p2sh_version: "c4",
794
+ privkey_version: "f1",
795
+ extended_privkey_version: "0432a243",
796
+ extended_pubkey_version: "0432a9a8",
797
+ default_port: 44556,
798
+ protocol_version: 70003,
799
+ min_tx_fee: COIN,
800
+ min_relay_tx_fee: COIN,
801
+ dust: COIN,
802
+ per_dust_fee: true,
803
+ free_tx_bytes: 26_000,
804
+ coinbase_maturity: 30,
805
+ coinbase_maturity_new: 240,
806
+ reward_base: 500_000 * COIN,
807
+ reward_halving: 100_000,
808
+ retarget_interval: 240,
809
+ retarget_time: 14400, # 4 hours
810
+ retarget_time_new: 60, # 1 minute
811
+ target_spacing: 60, # block interval
812
+ max_money: 100_000_000_000 * COIN,
813
+ dns_seeds: [
814
+ "testdoge-seed.lionservers.de",
815
+ ],
816
+ genesis_hash: "bb0a78264637406b6360aad926284d544d7049f45189db5664f3c4d07350559e",
817
+ proof_of_work_limit: 0x1e0fffff,
818
+ alert_pubkeys: [],
819
+ known_nodes: [
820
+ "localhost",
821
+ "testnets.chain.so",
822
+ ],
823
+ checkpoints: {
824
+ 546 => "ac537cfeda975e45040e9938d08e40a16e0fbd6388d02d9b4928b8ae0108c626",
825
+ },
826
+ auxpow_chain_id: 0x0062,
827
+ # Doge-specific hard-fork cutoffs
828
+ difficulty_change_block: 145000,
829
+ maturity_change_block: 145000,
830
+ reset_target_block: 157500,
831
+ auxpow_start_block: 158100
832
+ })
833
+
834
+ NETWORKS[:namecoin] = NETWORKS[:bitcoin].merge({
835
+ project: :namecoin,
836
+ magic_head: "\xF9\xBE\xB4\xFE",
837
+ address_version: "34",
838
+ default_port: 8334,
839
+ protocol_version: 35000,
840
+ min_tx_fee: 50_000,
841
+ per_dust_fee: true,
842
+ dns_seeds: [
843
+ "nmc.seed.quisquis.de",
844
+ "dnsseed.namecoin.webbtc.com",
845
+ ],
846
+ genesis_hash: "000000000062b72c5e2ceb45fbc8587e807c155b0da735e6483dfba2f0a9c770",
847
+ known_nodes: [
848
+ "bitcoin.tunl.in",
849
+ "namecoin.webbtc.com",
850
+ "178.32.31.41",
851
+ "78.47.86.43",
852
+ "69.164.206.88",
853
+ ],
854
+ checkpoints: {
855
+ 0 => "000000000062b72c5e2ceb45fbc8587e807c155b0da735e6483dfba2f0a9c770",
856
+ 19200 => "d8a7c3e01e1e95bcee015e6fcc7583a2ca60b79e5a3aa0a171eddd344ada903d",
857
+ 24000 => "425ab0983cf04f43f346a4ca53049d0dc2db952c0a68eb0b55c3bb64108d5371",
858
+ 97778 => "7553b1e43da01cfcda4335de1caf623e941d43894bd81c2af27b6582f9d83c6f",
859
+ 165000 => "823d7a54ebab04d14c4ba3508f6b5f25977406f4d389539eac0174d52c6b4b62",
860
+ },
861
+ auxpow_chain_id: 1
862
+ })
863
+
864
+ NETWORKS[:namecoin_testnet] = NETWORKS[:namecoin].merge({
865
+ magic_head: "\xFA\xBF\xB5\xFE",
866
+ default_port: 18334,
867
+ genesis_hash: "00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008",
868
+ dns_seeds: [
869
+ "dnsseed.test.namecoin.webbtc.com",
870
+ ],
871
+ known_nodes: [
872
+ "test.namecoin.webbtc.com",
873
+ "nmctest.net",
874
+ "192.99.247.234"],
875
+ checkpoints: { }
876
+ })
877
+
878
+ NETWORKS[:namecoin_regtest] = NETWORKS[:namecoin_testnet].merge({
879
+ magic_head: "\xFA\xBF\xB5\xDA",
880
+ default_port: 18445,
881
+ genesis_hash: "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206",
882
+ dns_seeds: [], known_nodes: [],
883
+ proof_of_work_limit: 0x207fffff,
884
+ checkpoints: { },
885
+ address_versions: { pubkey_hash: "6f", script_hash: "c4" },
886
+ privkey_version: "ef",
887
+ })
888
+
889
+ NETWORKS[:monacoin] = NETWORKS[:bitcoin].merge({
890
+ project: :monacoin,
891
+ magic_head: "\xFB\xC0\xB6\xDB",
892
+ address_version: "32",
893
+ default_port: 9402,
894
+ protocol_version: 70015,
895
+ min_tx_fee: 50_000,
896
+ per_dust_fee: true,
897
+ dns_seeds: [
898
+ "dnsseed.monacoin.org",
899
+ ],
900
+ genesis_hash: "a2b106ceba3be0c6d097b2a6a6aacf9d638ba8258ae478158f449c321061e0b2",
901
+ known_nodes: [
902
+ "202.219.180.37",
903
+ "110.50.96.23",
904
+ ],
905
+ checkpoints: {
906
+ 0 => "a2b106ceba3be0c6d097b2a6a6aacf9d638ba8258ae478158f449c321061e0b2",
907
+ 1500 => "9f42d51d18d0a8914a00664c433a0ca4be3eed02f9374d790bffbd3d3053d41d",
908
+ 4000 => "2c60edac7d9f44d90d1e218af2a8085e78b735185c5bf42f9fe9dbd0e604c97b",
909
+ 32000 => "c0703986c1c6a9052478db5e52432e5a1e55d6b6362b85f0ffdbb61ce3311b77",
910
+ 189250 => "1bea3d5c25a8097eef2e70ece4beb6c502b895fe00056552948309beb3497c99",
911
+ 1045000 => "562593372b8cee7d2eac325ef8874532d93cc031a75a00cec0086d2d943f40dc"
912
+ },
913
+ auxpow_chain_id: 1
914
+ })
915
+
916
+ NETWORKS[:monacoin_testnet] = NETWORKS[:monacoin].merge({
917
+ address_version: "6F",
918
+ magic_head: "\xFD\xD2\xC8\xF1",
919
+ default_port: 19402,
920
+ dns_seeds: [
921
+ "testnet-dnsseed.monacoin.org",
922
+ ],
923
+ genesis_hash: "a2b106ceba3be0c6d097b2a6a6aacf9d638ba8258ae478158f449c321061e0b2",
924
+ known_nodes: [
925
+ "153.120.39.89",
926
+ "160.16.208.215",
927
+ ],
928
+ checkpoints: {
929
+ 0 => "a2b106ceba3be0c6d097b2a6a6aacf9d638ba8258ae478158f449c321061e0b2",
930
+ },
931
+ auxpow_chain_id: 1
932
+ })
933
+ end