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 +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
|