monacoin-ruby 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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