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 +4 -4
- data/lib/bitcoin.rb +933 -0
- data/lib/bitcoin/bloom_filter.rb +125 -0
- data/lib/bitcoin/builder.rb +494 -0
- data/lib/bitcoin/connection.rb +130 -0
- data/lib/bitcoin/contracthash.rb +76 -0
- data/lib/bitcoin/dogecoin.rb +97 -0
- data/lib/bitcoin/electrum/mnemonic.rb +162 -0
- data/lib/bitcoin/ext_key.rb +191 -0
- data/lib/bitcoin/ffi/bitcoinconsensus.rb +75 -0
- data/lib/bitcoin/ffi/openssl.rb +388 -0
- data/lib/bitcoin/ffi/secp256k1.rb +266 -0
- data/lib/bitcoin/key.rb +280 -0
- data/lib/bitcoin/litecoin.rb +83 -0
- data/lib/bitcoin/logger.rb +86 -0
- data/lib/bitcoin/protocol.rb +189 -0
- data/lib/bitcoin/protocol/address.rb +50 -0
- data/lib/bitcoin/protocol/alert.rb +46 -0
- data/lib/bitcoin/protocol/aux_pow.rb +123 -0
- data/lib/bitcoin/protocol/block.rb +285 -0
- data/lib/bitcoin/protocol/handler.rb +43 -0
- data/lib/bitcoin/protocol/parser.rb +194 -0
- data/lib/bitcoin/protocol/partial_merkle_tree.rb +61 -0
- data/lib/bitcoin/protocol/reject.rb +38 -0
- data/lib/bitcoin/protocol/script_witness.rb +31 -0
- data/lib/bitcoin/protocol/tx.rb +587 -0
- data/lib/bitcoin/protocol/txin.rb +142 -0
- data/lib/bitcoin/protocol/txout.rb +95 -0
- data/lib/bitcoin/protocol/version.rb +88 -0
- data/lib/bitcoin/script.rb +1656 -0
- data/lib/bitcoin/trezor/mnemonic.rb +130 -0
- data/lib/bitcoin/version.rb +3 -0
- metadata +32 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5f657b65bdb51796fcaa25c6edde7918abf290860d50b2167bf861a99ecc7a7
|
4
|
+
data.tar.gz: b604b71b2b2fbb87b1230d749e6dcc6e4fc0c02e2421e5fba80d6de630a8b5a2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|